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