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