e5bce131ad13cbbd53cb41899c228852167b1949
[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                 chdir(class->dir);
392                 if(class->custom) {
393                         execv(argv[0], argv);
394         } else {
395             /* Default install is /usr/local/bin */
396             execv(LOCAL_MPG_123, argv);
397             /* Many places have it in /usr/bin */
398             execv(MPG_123, argv);
399             /* Check PATH as a last-ditch effort */
400             execvp("mpg123", argv);
401         }
402                 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
403                 close(fds[1]);
404                 exit(1);
405         } else {
406                 /* Parent */
407                 close(fds[1]);
408         }
409         return fds[0];
410 }
411
412 static void *monmp3thread(void *data)
413 {
414 #define MOH_MS_INTERVAL         100
415
416         struct mohclass *class = data;
417         struct mohdata *moh;
418         char buf[8192];
419         short sbuf[8192];
420         int res, res2;
421         struct timeval tv;
422         struct timeval tv_tmp;
423         long error_sec, error_usec;
424         long delay;
425
426         tv_tmp.tv_sec = 0;
427         tv_tmp.tv_usec = 0;
428         tv.tv_sec = 0;
429         tv.tv_usec = 0;
430         error_sec = 0;
431         error_usec = 0;
432         for(;/* ever */;) {
433                 /* Spawn mp3 player if it's not there */
434                 if (class->srcfd < 0) {
435                         if ((class->srcfd = spawn_mp3(class)) < 0) {
436                                 ast_log(LOG_WARNING, "unable to spawn mp3player\n");
437                                 /* Try again later */
438                                 sleep(500);
439                         }
440                 }
441                 if (class->pseudofd > -1) {
442                         /* Pause some amount of time */
443                         res = read(class->pseudofd, buf, sizeof(buf));
444                 } else {
445                         /* Reliable sleep */
446                         if (gettimeofday(&tv_tmp, NULL) < 0) {
447                                 ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
448                                 return NULL;
449                         }
450                         if (((unsigned long)(tv.tv_sec) > 0)&&((unsigned long)(tv.tv_usec) > 0)) {
451                                 if ((unsigned long)(tv_tmp.tv_usec) < (unsigned long)(tv.tv_usec)) {
452                                         tv_tmp.tv_usec += 1000000;
453                                         tv_tmp.tv_sec -= 1;
454                                 }
455                                 error_sec = (unsigned long)(tv_tmp.tv_sec) - (unsigned long)(tv.tv_sec);
456                                 error_usec = (unsigned long)(tv_tmp.tv_usec) - (unsigned long)(tv.tv_usec);
457                         } else {
458                                 error_sec = 0;
459                                 error_usec = 0;
460                         }
461                         if (error_sec * 1000 + error_usec / 1000 < MOH_MS_INTERVAL) {
462                                 tv.tv_sec = tv_tmp.tv_sec + (MOH_MS_INTERVAL/1000 - error_sec);
463                                 tv.tv_usec = tv_tmp.tv_usec + ((MOH_MS_INTERVAL % 1000) * 1000 - error_usec);
464                                 delay = (MOH_MS_INTERVAL/1000 - error_sec) * 1000 +
465                                                         ((MOH_MS_INTERVAL % 1000) * 1000 - error_usec) / 1000;
466                         } else {
467                                 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
468                                 tv.tv_sec = tv_tmp.tv_sec;
469                                 tv.tv_usec = tv_tmp.tv_usec;
470                                 delay = 0;
471                         }
472                         if (tv.tv_usec > 1000000) {
473                                 tv.tv_sec++;
474                                 tv.tv_usec-= 1000000;
475                         }
476                         if (delay > 0)
477                                 usleep(delay * 1000);
478                         res = 800;              /* 800 samples */
479                 }
480                 if (!class->members)
481                         continue;
482                 /* Read mp3 audio */
483                 if ((res2 = read(class->srcfd, sbuf, res * 2)) != res * 2) {
484                         if (!res2) {
485                                 close(class->srcfd);
486                                 class->srcfd = -1;
487                                 if (class->pid) {
488                                         kill(class->pid, SIGKILL);
489                                         class->pid = 0;
490                                 }
491                         } else
492                                 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, res * 2);
493                         continue;
494                 }
495                 ast_mutex_lock(&moh_lock);
496                 moh = class->members;
497                 while(moh) {
498                         /* Write data */
499                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) 
500                                 if (option_debug)
501                                         ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
502                         moh = moh->next;
503                 }
504                 ast_mutex_unlock(&moh_lock);
505         }
506         return NULL;
507 }
508
509 static int moh0_exec(struct ast_channel *chan, void *data)
510 {
511         if (ast_moh_start(chan, data)) {
512                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
513                 return -1;
514         }
515         while(!ast_safe_sleep(chan, 10000));
516         return -1;
517 }
518
519 static int moh1_exec(struct ast_channel *chan, void *data)
520 {
521         int res;
522         if (!data || !atoi(data)) {
523                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
524                 return -1;
525         }
526         if (ast_moh_start(chan, NULL)) {
527                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
528                 return -1;
529         }
530         res = ast_safe_sleep(chan, atoi(data) * 1000);
531         ast_moh_stop(chan);
532         return res;
533 }
534
535 static int moh2_exec(struct ast_channel *chan, void *data)
536 {
537         if (!data || ast_strlen_zero(data)) {
538                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
539                 return -1;
540         }
541         strncpy(chan->musicclass, data, sizeof(chan->musicclass) - 1);
542         return 0;
543 }
544
545 static struct mohclass *get_mohbyname(char *name)
546 {
547         struct mohclass *moh;
548         moh = mohclasses;
549         while(moh) {
550                 if (!strcasecmp(name, moh->class))
551                         return moh;
552                 moh = moh->next;
553         }
554         return NULL;
555 }
556
557 static struct mohdata *mohalloc(struct mohclass *cl)
558 {
559         struct mohdata *moh;
560         long flags;
561         moh = malloc(sizeof(struct mohdata));
562         if (!moh)
563                 return NULL;
564         memset(moh, 0, sizeof(struct mohdata));
565         if (pipe(moh->pipe)) {
566                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
567                 free(moh);
568                 return NULL;
569         }
570         /* Make entirely non-blocking */
571         flags = fcntl(moh->pipe[0], F_GETFL);
572         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
573         flags = fcntl(moh->pipe[1], F_GETFL);
574         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
575         moh->parent = cl;
576         moh->next = cl->members;
577         cl->members = moh;
578         return moh;
579 }
580
581 static void moh_release(struct ast_channel *chan, void *data)
582 {
583         struct mohdata *moh = data, *prev, *cur;
584         int oldwfmt;
585         ast_mutex_lock(&moh_lock);
586         /* Unlink */
587         prev = NULL;
588         cur = moh->parent->members;
589         while(cur) {
590                 if (cur == moh) {
591                         if (prev)
592                                 prev->next = cur->next;
593                         else
594                                 moh->parent->members = cur->next;
595                         break;
596                 }
597                 prev = cur;
598                 cur = cur->next;
599         }
600         ast_mutex_unlock(&moh_lock);
601         close(moh->pipe[0]);
602         close(moh->pipe[1]);
603         oldwfmt = moh->origwfmt;
604         free(moh);
605         if (chan) {
606                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
607                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
608                 if (option_verbose > 2)
609                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
610         }
611 }
612
613 static void *moh_alloc(struct ast_channel *chan, void *params)
614 {
615         struct mohdata *res;
616         struct mohclass *class;
617         class = params;
618         if (class)
619                 res = mohalloc(class);
620         else {
621                 if (strcasecmp(params, "default"))
622                         ast_log(LOG_WARNING, "No class: %s\n", (char *)params);
623                 res = NULL;
624         }
625         if (res) {
626                 res->origwfmt = chan->writeformat;
627                 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
628                         ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format\n", chan->name);
629                         moh_release(NULL, res);
630                         res = NULL;
631                 }
632                 if (option_verbose > 2)
633                         ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", (char *)params, chan->name);
634         }
635         return res;
636 }
637
638 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
639 {
640         struct ast_frame f;
641         struct mohdata *moh = data;
642         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
643         int res;
644         if(!moh->parent->pid)
645                 return - 1;
646         len = samples * 2;
647         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
648                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), (int)len, chan->name);
649                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
650         }
651         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
652 #if 0
653         if (res != len) {
654                 ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
655         }
656 #endif
657         if (res > 0) {
658                 memset(&f, 0, sizeof(f));
659                 f.frametype = AST_FRAME_VOICE;
660                 f.subclass = AST_FORMAT_SLINEAR;
661                 f.mallocd = 0;
662                 f.datalen = res;
663                 f.samples = res / 2;
664                 f.data = buf + AST_FRIENDLY_OFFSET / 2;
665                 f.offset = AST_FRIENDLY_OFFSET;
666                 if (ast_write(chan, &f)< 0) {
667                         ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
668                         return -1;
669                 }
670         }
671         return 0;
672 }
673
674 static struct ast_generator mohgen = 
675 {
676         alloc: moh_alloc,
677         release: moh_release,
678         generate: moh_generate,
679 };
680
681 static int moh_scan_files(struct mohclass *class) {
682
683         DIR *files_DIR;
684         struct dirent *files_dirent;
685         char path[512];
686         char filepath[MAX_MOHFILE_LEN];
687         char *ext;
688         struct stat statbuf;
689         int dirnamelen;
690         int i;
691         
692         files_DIR = opendir(class->dir);
693         if (!files_DIR) {
694                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
695                 return -1;
696         }
697
698         class->total_files = 0;
699         dirnamelen = strlen(class->dir) + 2;
700         getcwd(path, 512);
701         chdir(class->dir);
702         memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
703
704         while ((files_dirent = readdir(files_DIR))) {
705                 if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
706                         continue;
707
708                 snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
709
710                 if (stat(filepath, &statbuf))
711                         continue;
712
713                 if (!S_ISREG(statbuf.st_mode))
714                         continue;
715
716                 if ((ext = strrchr(filepath, '.')))
717                         *ext = '\0';
718
719                 /* check to see if this file's format can be opened */
720                 if (ast_fileexists(filepath, ext, NULL) == -1)
721                         continue;
722
723                 /* if the file is present in multiple formats, ensure we only put it into the list once */
724                 for (i = 0; i < class->total_files; i++)
725                         if (!strcmp(filepath, class->filearray[i]))
726                                 break;
727
728                 if (i == class->total_files)
729                         strcpy(class->filearray[class->total_files++], filepath);
730         }
731
732         closedir(files_DIR);
733         chdir(path);
734         return class->total_files;
735 }
736
737 static int moh_register(char *classname, char *mode, char *param, char *miscargs)
738 {
739         struct mohclass *moh;
740 #ifdef ZAPATA_MOH
741         int x;
742 #endif
743         ast_mutex_lock(&moh_lock);
744         moh = get_mohbyname(classname);
745         ast_mutex_unlock(&moh_lock);
746         if (moh) {
747                 ast_log(LOG_WARNING, "Music on Hold '%s' already exists\n", classname);
748                 return -1;
749         }
750         moh = malloc(sizeof(struct mohclass));
751         if (!moh)
752                 return -1;
753         memset(moh, 0, sizeof(struct mohclass));
754         time(&moh->start);
755         moh->start -= respawn_time;
756         strncpy(moh->class, classname, sizeof(moh->class) - 1);
757         if (miscargs) {
758                 strncpy(moh->miscargs, miscargs, sizeof(moh->miscargs) - 1);
759                 if (strchr(miscargs,'r'))
760                         moh->randomize=1;
761         }
762         if (!strcasecmp(mode, "files")) {
763                 if (param)
764                         strncpy(moh->dir, param, sizeof(moh->dir) - 1);
765                 if (!moh_scan_files(moh)) {
766                         free(moh);
767                         return -1;
768                 }
769         } else if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3") || !strcasecmp(mode, "custom")) {
770
771                 if (param)
772                         strncpy(moh->dir, param, sizeof(moh->dir) - 1);
773
774                 if (!strcasecmp(mode, "custom"))
775                         moh->custom = 1;
776                 else if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb"))
777                         moh->single = 1;
778                 else if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb"))
779                         moh->quiet = 1;
780                 
781                 moh->srcfd = -1;
782 #ifdef ZAPATA_MOH
783                 /* It's an MP3 Moh -- Open /dev/zap/pseudo for timing...  Is
784                    there a better, yet reliable way to do this? */
785                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
786                 if (moh->pseudofd < 0) {
787                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
788                 } else {
789                         x = 320;
790                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
791                 }
792 #else
793                 moh->pseudofd = -1;
794 #endif
795                 if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
796                         ast_log(LOG_WARNING, "Unable to create moh...\n");
797                         if (moh->pseudofd > -1)
798                                 close(moh->pseudofd);
799                         free(moh);
800                         return -1;
801                 }
802         } else {
803                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mode);
804                 free(moh);
805                 return -1;
806         }
807         ast_mutex_lock(&moh_lock);
808         moh->next = mohclasses;
809         mohclasses = moh;
810         ast_mutex_unlock(&moh_lock);
811         return 0;
812 }
813
814 static void local_ast_moh_cleanup(struct ast_channel *chan)
815 {
816         if(chan->music_state) {
817                 free(chan->music_state);
818                 chan->music_state = NULL;
819         }
820 }
821
822 static int local_ast_moh_start(struct ast_channel *chan, char *class)
823 {
824         struct mohclass *mohclass;
825
826         if (!class || ast_strlen_zero(class))
827                 class = chan->musicclass;
828         if (!class || ast_strlen_zero(class))
829                 class = "default";
830         ast_mutex_lock(&moh_lock);
831         mohclass = get_mohbyname(class);
832         ast_mutex_unlock(&moh_lock);
833
834         if (!mohclass) {
835                 ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
836                 return -1;
837         }
838
839         ast_set_flag(chan, AST_FLAG_MOH);
840         if (mohclass->total_files) {
841                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
842         } else
843                 return ast_activate_generator(chan, &mohgen, mohclass);
844 }
845
846 static void local_ast_moh_stop(struct ast_channel *chan)
847 {
848         ast_clear_flag(chan, AST_FLAG_MOH);
849         ast_deactivate_generator(chan);
850
851         if(chan->music_state) {
852                 if(chan->stream) {
853                         ast_closestream(chan->stream);
854                         chan->stream = NULL;
855                 }
856         }
857 }
858
859 static int load_moh_classes(void)
860 {
861         struct ast_config *cfg;
862         struct ast_variable *var;
863         char *data;
864         char *args;
865         int x = 0;
866         cfg = ast_load("musiconhold.conf");
867         if (cfg) {
868                 var = ast_variable_browse(cfg, "classes");
869                 while(var) {
870                         data = strchr(var->value, ':');
871                         if (data) {
872                                 *data = '\0';
873                                 data++;
874                                 args = strchr(data, ',');
875                                 if (args) {
876                                         *args = '\0';
877                                         args++;
878                                 }
879                                 if(!(get_mohbyname(var->name))) {
880                                         moh_register(var->name, var->value, data, args);
881                                         x++;
882                                 }
883                         }
884                         var = var->next;
885                 }
886                 var = ast_variable_browse(cfg, "moh_files");
887                 while(var) {
888                         if(!(get_mohbyname(var->name))) {
889                                 args = strchr(var->value, ',');
890                                 if (args) {
891                                         *args = '\0';
892                                         args++;
893                                 }
894                                 moh_register(var->name, "files", var->value, args);
895                                 x++;
896                         }
897                         var = var->next;
898                 }
899
900                 ast_destroy(cfg);
901         }
902         return x;
903 }
904
905 static void ast_moh_destroy(void)
906 {
907         struct mohclass *moh,*tmp;
908         char buff[8192];
909         int bytes, tbytes=0, stime = 0, pid = 0;
910         if (option_verbose > 1)
911                 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
912         ast_mutex_lock(&moh_lock);
913         moh = mohclasses;
914
915         while(moh) {
916                 if (moh->pid) {
917                         ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
918                         stime = time(NULL);
919                         pid = moh->pid;
920                         moh->pid = 0;
921                         kill(pid, SIGKILL);
922                         while ((bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime + 5) {
923                                 tbytes = tbytes + bytes;
924                         }
925                         ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
926                         close(moh->srcfd);
927                 }
928                 tmp = moh;
929                 moh = moh->next;
930                 free(tmp);
931         }
932         mohclasses = NULL;
933         ast_mutex_unlock(&moh_lock);
934 }
935
936
937 static void moh_on_off(int on) {
938         struct ast_channel *chan = ast_channel_walk_locked(NULL);
939         while(chan) {
940                 if(ast_test_flag(chan, AST_FLAG_MOH)) {
941                         if(on)
942                                 local_ast_moh_start(chan,NULL);
943                         else
944                                 ast_deactivate_generator(chan);
945                 }
946                 ast_mutex_unlock(&chan->lock);
947                 chan = ast_channel_walk_locked(chan);
948         }
949 }
950
951 static int moh_cli(int fd, int argc, char *argv[]) 
952 {
953         int x = 0;
954         moh_on_off(0);
955         ast_moh_destroy();
956         x = load_moh_classes();
957         moh_on_off(1);
958         ast_cli(fd,"\n%d class%s reloaded.\n",x,x == 1 ? "" : "es");
959         return 0;
960 }
961
962 static int cli_files_show(int fd, int argc, char *argv[])
963 {
964         int i;
965         struct mohclass *class;
966
967         ast_mutex_lock(&moh_lock);
968         for (class = mohclasses; class; class = class->next) {
969                 if (!class->total_files)
970                         continue;
971
972                 ast_cli(fd, "Class: %s\n", class->class);
973                 for (i = 0; i < class->total_files; i++)
974                         ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
975         }
976         ast_mutex_unlock(&moh_lock);
977
978         return 0;
979 }
980
981 static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
982
983 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};
984
985
986 int load_module(void)
987 {
988         int res;
989         load_moh_classes();
990         ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
991         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
992         ast_register_atexit(ast_moh_destroy);
993         ast_cli_register(&cli_moh);
994         ast_cli_register(&cli_moh_files_show);
995         if (!res)
996                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
997         if (!res)
998                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
999
1000         return res;
1001 }
1002
1003 int reload(void)
1004 {
1005     struct mohclass *moh = mohclasses;
1006     load_moh_classes();
1007     while(moh) {
1008         if (moh->total_files)
1009             moh_scan_files(moh);
1010         moh = moh->next;
1011     }
1012     return 0;
1013 }
1014
1015
1016 int unload_module(void)
1017 {
1018         return -1;
1019 }
1020
1021 char *description(void)
1022 {
1023         return "Music On Hold Resource";
1024 }
1025
1026 int usecount(void)
1027 {
1028         /* Never allow Music On Hold to be unloaded
1029            unresolve needed symbols in the dialer */
1030 #if 0
1031         int res;
1032         STANDARD_USECOUNT(res);
1033         return res;
1034 #else
1035         return 1;
1036 #endif
1037 }
1038
1039 char *key()
1040 {
1041         return ASTERISK_GPL_KEY;
1042 }