6040be1c68f06a857f5184be5905ff7d4b0a78bb
[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         ast_moh_stop(chan);
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 *ext;
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         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                         ext++;
719                 }
720
721                 /* check to see if this file's format can be opened */
722                 if (ast_fileexists(filepath, ext, NULL) == -1)
723                         continue;
724
725                 /* if the file is present in multiple formats, ensure we only put it into the list once */
726                 for (i = 0; i < class->total_files; i++)
727                         if (!strcmp(filepath, class->filearray[i]))
728                                 break;
729
730                 if (i == class->total_files)
731                         strcpy(class->filearray[class->total_files++], filepath);
732         }
733
734         closedir(files_DIR);
735         chdir(path);
736         return class->total_files;
737 }
738
739 static int moh_register(char *classname, char *mode, char *param, char *miscargs)
740 {
741         struct mohclass *moh;
742 #ifdef ZAPATA_MOH
743         int x;
744 #endif
745         ast_mutex_lock(&moh_lock);
746         moh = get_mohbyname(classname);
747         ast_mutex_unlock(&moh_lock);
748         if (moh) {
749                 ast_log(LOG_WARNING, "Music on Hold '%s' already exists\n", classname);
750                 return -1;
751         }
752         moh = malloc(sizeof(struct mohclass));
753         if (!moh)
754                 return -1;
755         memset(moh, 0, sizeof(struct mohclass));
756         time(&moh->start);
757         moh->start -= respawn_time;
758         strncpy(moh->class, classname, sizeof(moh->class) - 1);
759         if (miscargs) {
760                 strncpy(moh->miscargs, miscargs, sizeof(moh->miscargs) - 1);
761                 if (strchr(miscargs,'r'))
762                         moh->randomize=1;
763         }
764         if (!strcasecmp(mode, "files")) {
765                 if (param)
766                         strncpy(moh->dir, param, sizeof(moh->dir) - 1);
767                 if (!moh_scan_files(moh)) {
768                         free(moh);
769                         return -1;
770                 }
771         } else if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3") || !strcasecmp(mode, "custom")) {
772
773                 if (param)
774                         strncpy(moh->dir, param, sizeof(moh->dir) - 1);
775
776                 if (!strcasecmp(mode, "custom"))
777                         moh->custom = 1;
778                 else if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb"))
779                         moh->single = 1;
780                 else if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb"))
781                         moh->quiet = 1;
782                 
783                 moh->srcfd = -1;
784 #ifdef ZAPATA_MOH
785                 /* It's an MP3 Moh -- Open /dev/zap/pseudo for timing...  Is
786                    there a better, yet reliable way to do this? */
787                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
788                 if (moh->pseudofd < 0) {
789                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
790                 } else {
791                         x = 320;
792                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
793                 }
794 #else
795                 moh->pseudofd = -1;
796 #endif
797                 if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
798                         ast_log(LOG_WARNING, "Unable to create moh...\n");
799                         if (moh->pseudofd > -1)
800                                 close(moh->pseudofd);
801                         free(moh);
802                         return -1;
803                 }
804         } else {
805                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mode);
806                 free(moh);
807                 return -1;
808         }
809         ast_mutex_lock(&moh_lock);
810         moh->next = mohclasses;
811         mohclasses = moh;
812         ast_mutex_unlock(&moh_lock);
813         return 0;
814 }
815
816 static void local_ast_moh_cleanup(struct ast_channel *chan)
817 {
818         if(chan->music_state) {
819                 free(chan->music_state);
820                 chan->music_state = NULL;
821         }
822 }
823
824 static int local_ast_moh_start(struct ast_channel *chan, char *class)
825 {
826         struct mohclass *mohclass;
827
828         if (!class || ast_strlen_zero(class))
829                 class = chan->musicclass;
830         if (!class || ast_strlen_zero(class))
831                 class = "default";
832         ast_mutex_lock(&moh_lock);
833         mohclass = get_mohbyname(class);
834         ast_mutex_unlock(&moh_lock);
835
836         if (!mohclass) {
837                 ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
838                 return -1;
839         }
840
841         ast_set_flag(chan, AST_FLAG_MOH);
842         if (mohclass->total_files) {
843                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
844         } else
845                 return ast_activate_generator(chan, &mohgen, mohclass);
846 }
847
848 static void local_ast_moh_stop(struct ast_channel *chan)
849 {
850         ast_clear_flag(chan, AST_FLAG_MOH);
851         ast_deactivate_generator(chan);
852
853         if(chan->music_state) {
854                 if(chan->stream) {
855                         ast_closestream(chan->stream);
856                         chan->stream = NULL;
857                 }
858         }
859 }
860
861 static int load_moh_classes(void)
862 {
863         struct ast_config *cfg;
864         struct ast_variable *var;
865         char *data;
866         char *args;
867         int x = 0;
868         cfg = ast_load("musiconhold.conf");
869         if (cfg) {
870                 var = ast_variable_browse(cfg, "classes");
871                 while(var) {
872                         data = strchr(var->value, ':');
873                         if (data) {
874                                 *data = '\0';
875                                 data++;
876                                 args = strchr(data, ',');
877                                 if (args) {
878                                         *args = '\0';
879                                         args++;
880                                 }
881                                 if(!(get_mohbyname(var->name))) {
882                                         moh_register(var->name, var->value, data, args);
883                                         x++;
884                                 }
885                         }
886                         var = var->next;
887                 }
888                 var = ast_variable_browse(cfg, "moh_files");
889                 while(var) {
890                         if(!(get_mohbyname(var->name))) {
891                                 args = strchr(var->value, ',');
892                                 if (args) {
893                                         *args = '\0';
894                                         args++;
895                                 }
896                                 moh_register(var->name, "files", var->value, args);
897                                 x++;
898                         }
899                         var = var->next;
900                 }
901
902                 ast_destroy(cfg);
903         }
904         return x;
905 }
906
907 static void ast_moh_destroy(void)
908 {
909         struct mohclass *moh,*tmp;
910         char buff[8192];
911         int bytes, tbytes=0, stime = 0, pid = 0;
912         if (option_verbose > 1)
913                 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
914         ast_mutex_lock(&moh_lock);
915         moh = mohclasses;
916
917         while(moh) {
918                 if (moh->pid) {
919                         ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
920                         stime = time(NULL);
921                         pid = moh->pid;
922                         moh->pid = 0;
923                         kill(pid, SIGKILL);
924                         while ((bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime + 5) {
925                                 tbytes = tbytes + bytes;
926                         }
927                         ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
928                         close(moh->srcfd);
929                 }
930                 tmp = moh;
931                 moh = moh->next;
932                 free(tmp);
933         }
934         mohclasses = NULL;
935         ast_mutex_unlock(&moh_lock);
936 }
937
938
939 static void moh_on_off(int on) {
940         struct ast_channel *chan = ast_channel_walk_locked(NULL);
941         while(chan) {
942                 if(ast_test_flag(chan, AST_FLAG_MOH)) {
943                         if(on)
944                                 local_ast_moh_start(chan,NULL);
945                         else
946                                 ast_deactivate_generator(chan);
947                 }
948                 ast_mutex_unlock(&chan->lock);
949                 chan = ast_channel_walk_locked(chan);
950         }
951 }
952
953 static int moh_cli(int fd, int argc, char *argv[]) 
954 {
955         int x = 0;
956         moh_on_off(0);
957         ast_moh_destroy();
958         x = load_moh_classes();
959         moh_on_off(1);
960         ast_cli(fd,"\n%d class%s reloaded.\n",x,x == 1 ? "" : "es");
961         return 0;
962 }
963
964 static int cli_files_show(int fd, int argc, char *argv[])
965 {
966         int i;
967         struct mohclass *class;
968
969         ast_mutex_lock(&moh_lock);
970         for (class = mohclasses; class; class = class->next) {
971                 if (!class->total_files)
972                         continue;
973
974                 ast_cli(fd, "Class: %s\n", class->class);
975                 for (i = 0; i < class->total_files; i++)
976                         ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
977         }
978         ast_mutex_unlock(&moh_lock);
979
980         return 0;
981 }
982
983 static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
984
985 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};
986
987 static int init_classes(void) {
988     struct mohclass *moh;
989     load_moh_classes();
990         moh = mohclasses;
991     while(moh) {
992         if (moh->total_files)
993             moh_scan_files(moh);
994         moh = moh->next;
995     }
996         return 0;
997 }
998
999 int load_module(void)
1000 {
1001         int res;
1002         ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1003         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
1004         ast_register_atexit(ast_moh_destroy);
1005         ast_cli_register(&cli_moh);
1006         ast_cli_register(&cli_moh_files_show);
1007         if (!res)
1008                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
1009         if (!res)
1010                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
1011
1012         return init_classes();
1013 }
1014
1015 int reload(void)
1016 {
1017     return init_classes();
1018 }
1019
1020
1021 int unload_module(void)
1022 {
1023         return -1;
1024 }
1025
1026 char *description(void)
1027 {
1028         return "Music On Hold Resource";
1029 }
1030
1031 int usecount(void)
1032 {
1033         /* Never allow Music On Hold to be unloaded
1034            unresolve needed symbols in the dialer */
1035 #if 0
1036         int res;
1037         STANDARD_USECOUNT(res);
1038         return res;
1039 #else
1040         return 1;
1041 #endif
1042 }
1043
1044 char *key()
1045 {
1046         return ASTERISK_GPL_KEY;
1047 }