Merge anthm's native MOH patch (bug #2639) he promises me he'll rid it of ast_flag_moh...
[asterisk/asterisk.git] / res / res_musiconhold.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Routines implementing music on hold
5  * 
6  * Copyright (C) 1999-2004, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <../astconf.h>
20 #include <asterisk/options.h>
21 #include <asterisk/module.h>
22 #include <asterisk/translate.h>
23 #include <asterisk/say.h>
24 #include <asterisk/channel_pvt.h>
25 #include <asterisk/musiconhold.h>
26 #include <asterisk/config.h>
27 #include <asterisk/utils.h>
28 #include <stdlib.h>
29 #include <asterisk/cli.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <sys/time.h>
37 #include <sys/signal.h>
38 #include <netinet/in.h>
39 #include <sys/stat.h>
40 #include <dirent.h>
41 #ifdef ZAPATA_MOH
42 #ifdef __linux__
43 #include <linux/zaptel.h>
44 #else
45 #include <zaptel.h>
46 #endif /* __linux__ */
47 #endif
48 #include <unistd.h>
49 #include <sys/ioctl.h>
50 #define MAX_MOHFILES 512
51 #define MAX_MOHFILE_LEN 128
52
53 static char *app0 = "MusicOnHold";
54 static char *app1 = "WaitMusicOnHold";
55 static char *app2 = "SetMusicOnHold";
56
57 static char *synopsis0 = "Play Music On Hold indefinitely";
58 static char *synopsis1 = "Wait, playing Music On Hold";
59 static char *synopsis2 = "Set default Music On Hold class";
60
61 static char *descrip0 = "MusicOnHold(class): "
62 "Plays hold music specified by class.  If omitted, the default\n"
63 "music source for the channel will be used. Set the default \n"
64 "class with the SetMusicOnHold() application.\n"
65 "Returns -1 on hangup.\n"
66 "Never returns otherwise.\n";
67
68 static char *descrip1 = "WaitMusicOnHold(delay): "
69 "Plays hold music specified number of seconds.  Returns 0 when\n"
70 "done, or -1 on hangup.  If no hold music is available, the delay will\n"
71 "still occur with no sound.\n";
72
73 static char *descrip2 = "SetMusicOnHold(class): "
74 "Sets the default class for music on hold for a given channel.  When\n"
75 "music on hold is activated, this class will be used to select which\n"
76 "music is played.\n";
77
78 static int respawn_time = 20;
79
80 struct moh_files_state {
81         struct mohclass *class;
82         struct ast_filestream *stream;
83         int origwfmt;
84         int samples;
85         int sample_queue;
86         unsigned char pos;
87         unsigned char save_pos;
88 };
89
90 struct mohclass {
91         char class[80];
92         char dir[256];
93         char miscargs[256];
94         char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN];
95         int total_files;
96         int destroyme;
97         int pid;                /* PID of mpg123 */
98         int quiet;
99         int single;
100         int custom;
101         int randomize;
102         time_t start;
103         pthread_t thread;
104         struct mohdata *members;
105         /* Source of audio */
106         int srcfd;
107         /* FD for timing source */
108         int pseudofd;
109         struct mohclass *next;
110 };
111
112 struct mohdata {
113         int pipe[2];
114         int origwfmt;
115         struct mohclass *parent;
116         struct mohdata *next;
117 };
118
119 static struct mohclass *mohclasses;
120
121 AST_MUTEX_DEFINE_STATIC(moh_lock);
122
123 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
124 #define MPG_123 "/usr/bin/mpg123"
125 #define MAX_MP3S 256
126
127 static void moh_files_release(struct ast_channel *chan, void *data)
128 {
129         struct moh_files_state *state = chan->music_state;
130
131         if (chan && state) {
132                 if (option_verbose > 2)
133                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
134
135                 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
136                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
137                 }
138                 state->save_pos = state->pos + 1;
139         }
140 }
141
142
143 static int ast_moh_files_next(struct ast_channel *chan) {
144         struct moh_files_state *state = chan->music_state;
145
146         if(state->save_pos) {
147                 state->pos = state->save_pos - 1;
148                 state->save_pos = 0;
149         } else {
150                 state->samples = 0;
151                 if (chan->stream) {
152                         ast_closestream(chan->stream);
153                         chan->stream = NULL;
154                         state->pos++;
155                 }
156
157                 if (state->class->randomize) {
158                         srand(time(NULL)+getpid()+strlen(chan->name)-state->class->total_files);
159                         state->pos = rand();
160                 }
161         }
162
163         state->pos = state->pos % state->class->total_files;
164         
165         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
166                 ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
167                 return -1;
168         }
169         if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
170                 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
171                 state->pos++;
172                 return -1;
173         }
174
175         if (option_verbose > 2)
176                 ast_log(LOG_NOTICE, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
177
178
179         if (state->samples)
180                 ast_seekstream(chan->stream, state->samples, SEEK_SET);
181
182         return state->pos;
183 }
184
185
186 static struct ast_frame *moh_files_readframe(struct ast_channel *chan) {
187         struct ast_frame *f = NULL;
188         
189         if (!chan->stream || !(f = ast_readframe(chan->stream))) {
190                 if (ast_moh_files_next(chan) > -1)
191                         f = ast_readframe(chan->stream);
192         }
193
194         return f;
195 }
196
197 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
198 {
199         struct moh_files_state *state = chan->music_state;
200         struct ast_frame *f = NULL;
201         int res = 0;
202         state->sample_queue += samples;
203
204         while(state->sample_queue > 0) {
205                 if ((f = moh_files_readframe(chan))) {
206                         state->samples += f->samples;
207                         res = ast_write(chan, f);
208                         ast_frfree(f);
209                         if(res < 0) {
210                                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
211                                 return -1;
212                         }
213                         state->sample_queue -= f->samples;
214                 } else
215                         return -1;      
216         }
217         return res;
218 }
219
220
221 static void *moh_files_alloc(struct ast_channel *chan, void *params)
222 {
223         struct moh_files_state *state;
224         struct mohclass *class = params;
225         int allocated = 0;
226
227         if ((!chan->music_state) && ((state = malloc(sizeof(struct moh_files_state))))) {
228                 chan->music_state = state;
229                 allocated = 1;
230         } else 
231                 state = chan->music_state;
232
233
234         if(state) {
235                 if (allocated || state->class != class) {
236                         /* initialize */
237                         memset(state, 0, sizeof(struct moh_files_state));
238                         state->class = class;
239                 }
240
241                 state->origwfmt = chan->writeformat;
242
243                 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
244                         ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
245                         free(chan->music_state);
246                         chan->music_state = NULL;
247                 } else {
248                         if (option_verbose > 2)
249                                 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", (char *)params, chan->name);
250                 }
251
252
253         }
254         
255         return chan->music_state;
256 }
257
258 static struct ast_generator moh_file_stream = 
259 {
260         alloc: moh_files_alloc,
261         release: moh_files_release,
262         generate: moh_files_generator,
263 };
264
265 static int spawn_mp3(struct mohclass *class)
266 {
267         int fds[2];
268         int files=0;
269         char fns[MAX_MP3S][80];
270         char *argv[MAX_MP3S + 50];
271         char xargs[256];
272         char *argptr;
273         int argc = 0;
274         DIR *dir;
275         struct dirent *de;
276
277         
278         dir = opendir(class->dir);
279         if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
280                 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
281                 return -1;
282         }
283
284         if (!class->custom) {
285                 argv[argc++] = "mpg123";
286                 argv[argc++] = "-q";
287                 argv[argc++] = "-s";
288                 argv[argc++] = "--mono";
289                 argv[argc++] = "-r";
290                 argv[argc++] = "8000";
291                 
292                 if (!class->single) {
293                         argv[argc++] = "-b";
294                         argv[argc++] = "2048";
295                 }
296                 
297                 argv[argc++] = "-f";
298                 
299                 if (class->quiet)
300                         argv[argc++] = "4096";
301                 else
302                         argv[argc++] = "8192";
303                 
304                 /* Look for extra arguments and add them to the list */
305                 strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
306                 argptr = xargs;
307                 while(argptr && !ast_strlen_zero(argptr)) {
308                         argv[argc++] = argptr;
309                         argptr = strchr(argptr, ',');
310                         if (argptr) {
311                                 *argptr = '\0';
312                                 argptr++;
313                         }
314                 }
315         } else  {
316                 /* Format arguments for argv vector */
317                 strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
318                 argptr = xargs;
319                 while(argptr && !ast_strlen_zero(argptr)) {
320                         argv[argc++] = argptr;
321                         argptr = strchr(argptr, ' ');
322                         if (argptr) {
323                                 *argptr = '\0';
324                                 argptr++;
325                         }
326                 }
327         }
328
329         files = 0;
330         if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
331                 strncpy(fns[files], class->dir, sizeof(fns[files]) - 1);
332                 argv[argc++] = fns[files];
333                 files++;
334         } else {
335                 while((de = readdir(dir)) && (files < MAX_MP3S)) {
336                         if ((strlen(de->d_name) > 3) && 
337                                 ((class->custom && 
338                                   (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
339                                    !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln")))
340                                  || !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
341                                 strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1);
342                                 argv[argc++] = fns[files];
343                                 files++;
344                         }
345                 }
346         }
347         argv[argc] = NULL;
348         closedir(dir);
349         
350         if (pipe(fds)) {        
351                 ast_log(LOG_WARNING, "Pipe failed\n");
352                 return -1;
353         }
354 #if 0
355         printf("%d files total, %d args total\n", files, argc);
356         {
357                 int x;
358                 for (x=0;argv[x];x++)
359                         printf("arg%d: %s\n", x, argv[x]);
360         }
361 #endif  
362         if (!files) {
363                 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
364                 close(fds[0]);
365                 close(fds[1]);
366                 return -1;
367         }
368         if (time(NULL) - class->start < respawn_time) {
369                 sleep(respawn_time - (time(NULL) - class->start));
370         }
371         time(&class->start);
372         class->pid = fork();
373         if (class->pid < 0) {
374                 close(fds[0]);
375                 close(fds[1]);
376                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
377                 return -1;
378         }
379         if (!class->pid) {
380                 int x;
381                 close(fds[0]);
382                 /* Stdout goes to pipe */
383                 dup2(fds[1], STDOUT_FILENO);
384                 /* Close unused file descriptors */
385                 for (x=3;x<8192;x++) {
386                         if (-1 != fcntl(x, F_GETFL)) {
387                                 close(x);
388                         }
389                 }
390         /* Child */
391
392         if(class->custom) {
393                         chdir(class->dir);
394                         execv(argv[0], argv);
395         } else {
396             /* Default install is /usr/local/bin */
397             execv(LOCAL_MPG_123, argv);
398             /* Many places have it in /usr/bin */
399             execv(MPG_123, argv);
400             /* Check PATH as a last-ditch effort */
401             execvp("mpg123", argv);
402         }
403                 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
404                 close(fds[1]);
405                 exit(1);
406         } else {
407                 /* Parent */
408                 close(fds[1]);
409         }
410         return fds[0];
411 }
412
413 static void *monmp3thread(void *data)
414 {
415 #define MOH_MS_INTERVAL         100
416
417         struct mohclass *class = data;
418         struct mohdata *moh;
419         char buf[8192];
420         short sbuf[8192];
421         int res, res2;
422         struct timeval tv;
423         struct timeval tv_tmp;
424         long error_sec, error_usec;
425         long delay;
426
427         tv_tmp.tv_sec = 0;
428         tv_tmp.tv_usec = 0;
429         tv.tv_sec = 0;
430         tv.tv_usec = 0;
431         error_sec = 0;
432         error_usec = 0;
433         for(;/* ever */;) {
434                 /* Spawn mp3 player if it's not there */
435                 if (class->srcfd < 0) {
436                         if ((class->srcfd = spawn_mp3(class)) < 0) {
437                                 ast_log(LOG_WARNING, "unable to spawn mp3player\n");
438                                 /* Try again later */
439                                 sleep(500);
440                         }
441                 }
442                 if (class->pseudofd > -1) {
443                         /* Pause some amount of time */
444                         res = read(class->pseudofd, buf, sizeof(buf));
445                 } else {
446                         /* Reliable sleep */
447                         if (gettimeofday(&tv_tmp, NULL) < 0) {
448                                 ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
449                                 return NULL;
450                         }
451                         if (((unsigned long)(tv.tv_sec) > 0)&&((unsigned long)(tv.tv_usec) > 0)) {
452                                 if ((unsigned long)(tv_tmp.tv_usec) < (unsigned long)(tv.tv_usec)) {
453                                         tv_tmp.tv_usec += 1000000;
454                                         tv_tmp.tv_sec -= 1;
455                                 }
456                                 error_sec = (unsigned long)(tv_tmp.tv_sec) - (unsigned long)(tv.tv_sec);
457                                 error_usec = (unsigned long)(tv_tmp.tv_usec) - (unsigned long)(tv.tv_usec);
458                         } else {
459                                 error_sec = 0;
460                                 error_usec = 0;
461                         }
462                         if (error_sec * 1000 + error_usec / 1000 < MOH_MS_INTERVAL) {
463                                 tv.tv_sec = tv_tmp.tv_sec + (MOH_MS_INTERVAL/1000 - error_sec);
464                                 tv.tv_usec = tv_tmp.tv_usec + ((MOH_MS_INTERVAL % 1000) * 1000 - error_usec);
465                                 delay = (MOH_MS_INTERVAL/1000 - error_sec) * 1000 +
466                                                         ((MOH_MS_INTERVAL % 1000) * 1000 - error_usec) / 1000;
467                         } else {
468                                 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
469                                 tv.tv_sec = tv_tmp.tv_sec;
470                                 tv.tv_usec = tv_tmp.tv_usec;
471                                 delay = 0;
472                         }
473                         if (tv.tv_usec > 1000000) {
474                                 tv.tv_sec++;
475                                 tv.tv_usec-= 1000000;
476                         }
477                         if (delay > 0)
478                                 usleep(delay * 1000);
479                         res = 800;              /* 800 samples */
480                 }
481                 if (!class->members)
482                         continue;
483                 /* Read mp3 audio */
484                 if ((res2 = read(class->srcfd, sbuf, res * 2)) != res * 2) {
485                         if (!res2) {
486                                 close(class->srcfd);
487                                 class->srcfd = -1;
488                                 if (class->pid) {
489                                         kill(class->pid, SIGKILL);
490                                         class->pid = 0;
491                                 }
492                         } else
493                                 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, res * 2);
494                         continue;
495                 }
496                 ast_mutex_lock(&moh_lock);
497                 moh = class->members;
498                 while(moh) {
499                         /* Write data */
500                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) 
501                                 if (option_debug)
502                                         ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
503                         moh = moh->next;
504                 }
505                 ast_mutex_unlock(&moh_lock);
506         }
507         return NULL;
508 }
509
510 static int moh0_exec(struct ast_channel *chan, void *data)
511 {
512         if (ast_moh_start(chan, data)) {
513                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
514                 return -1;
515         }
516         while(!ast_safe_sleep(chan, 10000));
517         return -1;
518 }
519
520 static int moh1_exec(struct ast_channel *chan, void *data)
521 {
522         int res;
523         if (!data || !atoi(data)) {
524                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
525                 return -1;
526         }
527         if (ast_moh_start(chan, NULL)) {
528                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
529                 return -1;
530         }
531         res = ast_safe_sleep(chan, atoi(data) * 1000);
532         ast_moh_stop(chan);
533         return res;
534 }
535
536 static int moh2_exec(struct ast_channel *chan, void *data)
537 {
538         if (!data || ast_strlen_zero(data)) {
539                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
540                 return -1;
541         }
542         strncpy(chan->musicclass, data, sizeof(chan->musicclass) - 1);
543         return 0;
544 }
545
546 static struct mohclass *get_mohbyname(char *name)
547 {
548         struct mohclass *moh;
549         moh = mohclasses;
550         while(moh) {
551                 if (!strcasecmp(name, moh->class))
552                         return moh;
553                 moh = moh->next;
554         }
555         return NULL;
556 }
557
558 static struct mohdata *mohalloc(struct mohclass *cl)
559 {
560         struct mohdata *moh;
561         long flags;
562         moh = malloc(sizeof(struct mohdata));
563         if (!moh)
564                 return NULL;
565         memset(moh, 0, sizeof(struct mohdata));
566         if (pipe(moh->pipe)) {
567                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
568                 free(moh);
569                 return NULL;
570         }
571         /* Make entirely non-blocking */
572         flags = fcntl(moh->pipe[0], F_GETFL);
573         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
574         flags = fcntl(moh->pipe[1], F_GETFL);
575         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
576         moh->parent = cl;
577         moh->next = cl->members;
578         cl->members = moh;
579         return moh;
580 }
581
582 static void moh_release(struct ast_channel *chan, void *data)
583 {
584         struct mohdata *moh = data, *prev, *cur;
585         int oldwfmt;
586         ast_mutex_lock(&moh_lock);
587         /* Unlink */
588         prev = NULL;
589         cur = moh->parent->members;
590         while(cur) {
591                 if (cur == moh) {
592                         if (prev)
593                                 prev->next = cur->next;
594                         else
595                                 moh->parent->members = cur->next;
596                         break;
597                 }
598                 prev = cur;
599                 cur = cur->next;
600         }
601         ast_mutex_unlock(&moh_lock);
602         close(moh->pipe[0]);
603         close(moh->pipe[1]);
604         oldwfmt = moh->origwfmt;
605         free(moh);
606         if (chan) {
607                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
608                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
609                 if (option_verbose > 2)
610                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
611         }
612 }
613
614 static void *moh_alloc(struct ast_channel *chan, void *params)
615 {
616         struct mohdata *res;
617         struct mohclass *class;
618         class = params;
619         if (class)
620                 res = mohalloc(class);
621         else {
622                 if (strcasecmp(params, "default"))
623                         ast_log(LOG_WARNING, "No class: %s\n", (char *)params);
624                 res = NULL;
625         }
626         if (res) {
627                 res->origwfmt = chan->writeformat;
628                 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
629                         ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format\n", chan->name);
630                         moh_release(NULL, res);
631                         res = NULL;
632                 }
633                 if (option_verbose > 2)
634                         ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", (char *)params, chan->name);
635         }
636         return res;
637 }
638
639 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
640 {
641         struct ast_frame f;
642         struct mohdata *moh = data;
643         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
644         int res;
645         if(!moh->parent->pid)
646                 return - 1;
647         len = samples * 2;
648         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
649                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), (int)len, chan->name);
650                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
651         }
652         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
653 #if 0
654         if (res != len) {
655                 ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
656         }
657 #endif
658         if (res > 0) {
659                 memset(&f, 0, sizeof(f));
660                 f.frametype = AST_FRAME_VOICE;
661                 f.subclass = AST_FORMAT_SLINEAR;
662                 f.mallocd = 0;
663                 f.datalen = res;
664                 f.samples = res / 2;
665                 f.data = buf + AST_FRIENDLY_OFFSET / 2;
666                 f.offset = AST_FRIENDLY_OFFSET;
667                 if (ast_write(chan, &f)< 0) {
668                         ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
669                         return -1;
670                 }
671         }
672         return 0;
673 }
674
675 static struct ast_generator mohgen = 
676 {
677         alloc: moh_alloc,
678         release: moh_release,
679         generate: moh_generate,
680 };
681
682 static int moh_scan_files(struct mohclass *class) {
683
684         DIR *files_DIR;
685         struct dirent *files_dirent;
686         char path[512];
687         char filepath[MAX_MOHFILE_LEN];
688         char *scan;
689         struct stat statbuf;
690         int dirnamelen;
691         int i;
692         
693         files_DIR = opendir(class->dir);
694         if (!files_DIR) {
695                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
696                 return -1;
697         }
698
699         class->total_files = 0;
700         dirnamelen = strlen(class->dir) + 2;
701         getcwd(path, 512);
702         chdir(class->dir);
703         memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
704
705         while ((files_dirent = readdir(files_DIR))) {
706                 if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
707                         continue;
708
709                 snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
710
711                 if (stat(filepath, &statbuf))
712                         continue;
713
714                 if (!S_ISREG(statbuf.st_mode))
715                         continue;
716
717                 if ((scan = strrchr(filepath, '.')))
718                         *scan = '\0';
719
720                 /* if the file is present in multiple formats, ensure we only put it into the list once */
721                 for (i = 0; i < class->total_files; i++)
722                         if (!strcmp(filepath, class->filearray[i]))
723                                 break;
724
725                 if (i == class->total_files)
726                         strcpy(class->filearray[class->total_files++], filepath);
727         }
728
729         closedir(files_DIR);
730         chdir(path);
731         return class->total_files;
732 }
733
734 static int moh_register(char *classname, char *mode, char *param, char *miscargs)
735 {
736         struct mohclass *moh;
737 #ifdef ZAPATA_MOH
738         int x;
739 #endif
740         ast_mutex_lock(&moh_lock);
741         moh = get_mohbyname(classname);
742         ast_mutex_unlock(&moh_lock);
743         if (moh) {
744                 ast_log(LOG_WARNING, "Music on Hold '%s' already exists\n", classname);
745                 return -1;
746         }
747         moh = malloc(sizeof(struct mohclass));
748         if (!moh)
749                 return -1;
750         memset(moh, 0, sizeof(struct mohclass));
751         time(&moh->start);
752         moh->start -= respawn_time;
753         strncpy(moh->class, classname, sizeof(moh->class) - 1);
754         if (miscargs) {
755                 strncpy(moh->miscargs, miscargs, sizeof(moh->miscargs) - 1);
756                 if (strchr(miscargs,'r'))
757                         moh->randomize=1;
758         }
759         if (!strcasecmp(mode, "files")) {
760                 if (param)
761                         strncpy(moh->dir, param, sizeof(moh->dir) - 1);
762                 if (!moh_scan_files(moh)) {
763                         free(moh);
764                         return -1;
765                 }
766         } else if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3") || !strcasecmp(mode, "custom")) {
767
768                 if (param)
769                         strncpy(moh->dir, param, sizeof(moh->dir) - 1);
770
771                 if (!strcasecmp(mode, "custom"))
772                         moh->custom = 1;
773                 else if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb"))
774                         moh->single = 1;
775                 else if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb"))
776                         moh->quiet = 1;
777                 
778                 moh->srcfd = -1;
779 #ifdef ZAPATA_MOH
780                 /* It's an MP3 Moh -- Open /dev/zap/pseudo for timing...  Is
781                    there a better, yet reliable way to do this? */
782                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
783                 if (moh->pseudofd < 0) {
784                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
785                 } else {
786                         x = 320;
787                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
788                 }
789 #else
790                 moh->pseudofd = -1;
791 #endif
792                 if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
793                         ast_log(LOG_WARNING, "Unable to create moh...\n");
794                         if (moh->pseudofd > -1)
795                                 close(moh->pseudofd);
796                         free(moh);
797                         return -1;
798                 }
799         } else {
800                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mode);
801                 free(moh);
802                 return -1;
803         }
804         ast_mutex_lock(&moh_lock);
805         moh->next = mohclasses;
806         mohclasses = moh;
807         ast_mutex_unlock(&moh_lock);
808         return 0;
809 }
810
811 static void local_ast_moh_cleanup(struct ast_channel *chan)
812 {
813         if(chan->music_state) {
814                 free(chan->music_state);
815                 chan->music_state = NULL;
816         }
817 }
818
819 static int local_ast_moh_start(struct ast_channel *chan, char *class)
820 {
821         struct mohclass *mohclass;
822
823         if (!class || ast_strlen_zero(class))
824                 class = chan->musicclass;
825         if (!class || ast_strlen_zero(class))
826                 class = "default";
827         ast_mutex_lock(&moh_lock);
828         mohclass = get_mohbyname(class);
829         ast_mutex_unlock(&moh_lock);
830
831         if (!mohclass) {
832                 ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
833                 return -1;
834         }
835
836         ast_set_flag(chan, AST_FLAG_MOH);
837         if (mohclass->total_files) {
838                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
839         } else
840                 return ast_activate_generator(chan, &mohgen, mohclass);
841 }
842
843 static void local_ast_moh_stop(struct ast_channel *chan)
844 {
845         ast_clear_flag(chan, AST_FLAG_MOH);
846         ast_deactivate_generator(chan);
847
848         if(chan->music_state) {
849                 if(chan->stream) {
850                         ast_closestream(chan->stream);
851                         chan->stream = NULL;
852                 }
853         }
854 }
855
856 static int load_moh_classes(void)
857 {
858         struct ast_config *cfg;
859         struct ast_variable *var;
860         char *data;
861         char *args;
862         int x = 0;
863         cfg = ast_load("musiconhold.conf");
864         if (cfg) {
865                 var = ast_variable_browse(cfg, "classes");
866                 while(var) {
867                         data = strchr(var->value, ':');
868                         if (data) {
869                                 *data = '\0';
870                                 data++;
871                                 args = strchr(data, ',');
872                                 if (args) {
873                                         *args = '\0';
874                                         args++;
875                                 }
876                                 if(!(get_mohbyname(var->name))) {
877                                         moh_register(var->name, var->value, data, args);
878                                         x++;
879                                 }
880                         }
881                         var = var->next;
882                 }
883                 var = ast_variable_browse(cfg, "moh_files");
884                 while(var) {
885                         if(!(get_mohbyname(var->name))) {
886                                 args = strchr(var->value, ',');
887                                 if (args) {
888                                         *args = '\0';
889                                         args++;
890                                 }
891                                 moh_register(var->name, "files", var->value, args);
892                                 x++;
893                         }
894                         var = var->next;
895                 }
896
897                 ast_destroy(cfg);
898         }
899         return x;
900 }
901
902 static void ast_moh_destroy(void)
903 {
904         struct mohclass *moh,*tmp;
905         char buff[8192];
906         int bytes, tbytes=0, stime = 0, pid = 0;
907         if (option_verbose > 1)
908                 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
909         ast_mutex_lock(&moh_lock);
910         moh = mohclasses;
911
912         while(moh) {
913                 if (moh->pid) {
914                         ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
915                         stime = time(NULL);
916                         pid = moh->pid;
917                         moh->pid = 0;
918                         kill(pid, SIGKILL);
919                         while ((bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime + 5) {
920                                 tbytes = tbytes + bytes;
921                         }
922                         ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
923                         close(moh->srcfd);
924                 }
925                 tmp = moh;
926                 moh = moh->next;
927                 free(tmp);
928         }
929         mohclasses = NULL;
930         ast_mutex_unlock(&moh_lock);
931 }
932
933
934 static void moh_on_off(int on) {
935         struct ast_channel *chan = ast_channel_walk_locked(NULL);
936         while(chan) {
937                 if(ast_test_flag(chan, AST_FLAG_MOH)) {
938                         if(on)
939                                 local_ast_moh_start(chan,NULL);
940                         else
941                                 ast_deactivate_generator(chan);
942                 }
943                 ast_mutex_unlock(&chan->lock);
944                 chan = ast_channel_walk_locked(chan);
945         }
946 }
947
948 static int moh_cli(int fd, int argc, char *argv[]) 
949 {
950         int x = 0;
951         moh_on_off(0);
952         ast_moh_destroy();
953         x = load_moh_classes();
954         moh_on_off(1);
955         ast_cli(fd,"\n%d class%s reloaded.\n",x,x == 1 ? "" : "es");
956         return 0;
957 }
958
959 static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
960
961
962 int load_module(void)
963 {
964         int res;
965         load_moh_classes();
966         ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
967         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
968         ast_register_atexit(ast_moh_destroy);
969         ast_cli_register(&cli_moh);
970         if (!res)
971                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
972         if (!res)
973                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
974
975         return res;
976 }
977
978 int reload(void)
979 {
980     struct mohclass *moh = mohclasses;
981     load_moh_classes();
982     while(moh) {
983         if (moh->total_files)
984             moh_scan_files(moh);
985         moh = moh->next;
986     }
987     return 0;
988 }
989
990
991 int unload_module(void)
992 {
993         return -1;
994 }
995
996 char *description(void)
997 {
998         return "Music On Hold Resource";
999 }
1000
1001 int usecount(void)
1002 {
1003         /* Never allow Music On Hold to be unloaded
1004            unresolve needed symbols in the dialer */
1005 #if 0
1006         int res;
1007         STANDARD_USECOUNT(res);
1008         return res;
1009 #else
1010         return 1;
1011 #endif
1012 }
1013
1014 char *key()
1015 {
1016         return ASTERISK_GPL_KEY;
1017 }