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