more strncpy/ast_copy_string replacement
[asterisk/asterisk.git] / res / res_musiconhold.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Routines implementing music on hold
22  *
23  * \arg See also \ref Config_moh
24  * 
25  * \author Mark Spencer <markster@digium.com>
26  */
27
28 #include <stdlib.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
50 #include "asterisk.h"
51
52 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
53
54 #include "asterisk/lock.h"
55 #include "asterisk/file.h"
56 #include "asterisk/logger.h"
57 #include "asterisk/channel.h"
58 #include "asterisk/pbx.h"
59 #include "asterisk/options.h"
60 #include "asterisk/module.h"
61 #include "asterisk/translate.h"
62 #include "asterisk/say.h"
63 #include "asterisk/musiconhold.h"
64 #include "asterisk/config.h"
65 #include "asterisk/utils.h"
66 #include "asterisk/cli.h"
67 #include "asterisk/stringfields.h"
68
69 #define MAX_MOHFILES 512
70 #define MAX_MOHFILE_LEN 128
71
72 static char *app0 = "MusicOnHold";
73 static char *app1 = "WaitMusicOnHold";
74 static char *app2 = "SetMusicOnHold";
75 static char *app3 = "StartMusicOnHold";
76 static char *app4 = "StopMusicOnHold";
77
78 static char *synopsis0 = "Play Music On Hold indefinitely";
79 static char *synopsis1 = "Wait, playing Music On Hold";
80 static char *synopsis2 = "Set default Music On Hold class";
81 static char *synopsis3 = "Play Music On Hold";
82 static char *synopsis4 = "Stop Playing Music On Hold";
83
84 static char *descrip0 = "MusicOnHold(class): "
85 "Plays hold music specified by class.  If omitted, the default\n"
86 "music source for the channel will be used. Set the default \n"
87 "class with the SetMusicOnHold() application.\n"
88 "Returns -1 on hangup.\n"
89 "Never returns otherwise.\n";
90
91 static char *descrip1 = "WaitMusicOnHold(delay): "
92 "Plays hold music specified number of seconds.  Returns 0 when\n"
93 "done, or -1 on hangup.  If no hold music is available, the delay will\n"
94 "still occur with no sound.\n";
95
96 static char *descrip2 = "SetMusicOnHold(class): "
97 "Sets the default class for music on hold for a given channel.  When\n"
98 "music on hold is activated, this class will be used to select which\n"
99 "music is played.\n";
100
101 static char *descrip3 = "StartMusicOnHold(class): "
102 "Starts playing music on hold, uses default music class for channel.\n"
103 "Starts playing music specified by class.  If omitted, the default\n"
104 "music source for the channel will be used.  Always returns 0.\n";
105
106 static char *descrip4 = "StopMusicOnHold: "
107 "Stops playing music on hold.\n";
108
109 static int respawn_time = 20;
110
111 struct moh_files_state {
112         struct mohclass *class;
113         int origwfmt;
114         int samples;
115         int sample_queue;
116         unsigned char pos;
117         unsigned char save_pos;
118 };
119
120 #define MOH_QUIET               (1 << 0)
121 #define MOH_SINGLE              (1 << 1)
122 #define MOH_CUSTOM              (1 << 2)
123 #define MOH_RANDOMIZE           (1 << 3)
124
125 struct mohclass {
126         char name[MAX_MUSICCLASS];
127         char dir[256];
128         char args[256];
129         char mode[80];
130         char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN];
131         unsigned int flags;
132         int total_files;
133         int format;
134         int pid;                /* PID of mpg123 */
135         time_t start;
136         pthread_t thread;
137         struct mohdata *members;
138         /* Source of audio */
139         int srcfd;
140         /* FD for timing source */
141         int pseudofd;
142         struct mohclass *next;
143 };
144
145 struct mohdata {
146         int pipe[2];
147         int origwfmt;
148         struct mohclass *parent;
149         struct mohdata *next;
150 };
151
152 static struct mohclass *mohclasses;
153
154 AST_MUTEX_DEFINE_STATIC(moh_lock);
155
156 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
157 #define MPG_123 "/usr/bin/mpg123"
158 #define MAX_MP3S 256
159
160
161 static void ast_moh_free_class(struct mohclass **class) 
162 {
163         struct mohdata *members, *mtmp;
164         
165         members = (*class)->members;
166         while(members) {
167                 mtmp = members;
168                 members = members->next;
169                 free(mtmp);
170         }
171         if ((*class)->thread) {
172                 pthread_cancel((*class)->thread);
173                 (*class)->thread = 0;
174         }
175         free(*class);
176         *class = NULL;
177 }
178
179
180 static void moh_files_release(struct ast_channel *chan, void *data)
181 {
182         struct moh_files_state *state = chan->music_state;
183
184         if (chan && state) {
185                 if (option_verbose > 2)
186                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
187
188                 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
189                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
190                 }
191                 state->save_pos = state->pos + 1;
192         }
193 }
194
195
196 static int ast_moh_files_next(struct ast_channel *chan) 
197 {
198         struct moh_files_state *state = chan->music_state;
199         int tries;
200
201         if (state->save_pos) {
202                 state->pos = state->save_pos - 1;
203                 state->save_pos = 0;
204         } else {
205                 /* Try 20 times to find something good */
206                 for (tries=0;tries < 20;tries++) {
207                         state->samples = 0;
208                         if (chan->stream) {
209                                 ast_closestream(chan->stream);
210                                 chan->stream = NULL;
211                                 state->pos++;
212                         }
213
214                         if (ast_test_flag(state->class, MOH_RANDOMIZE))
215                                 state->pos = ast_random();
216
217                         /* check to see if this file's format can be opened */
218                         if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) != -1)
219                                 break;
220
221                 }
222         }
223
224         state->pos = state->pos % state->class->total_files;
225         
226         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
227                 ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
228                 return -1;
229         }
230         if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
231                 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
232                 state->pos++;
233                 return -1;
234         }
235
236         if (option_debug)
237                 ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
238
239         if (state->samples)
240                 ast_seekstream(chan->stream, state->samples, SEEK_SET);
241
242         return 0;
243 }
244
245
246 static struct ast_frame *moh_files_readframe(struct ast_channel *chan) 
247 {
248         struct ast_frame *f = NULL;
249         
250         if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
251                 if (!ast_moh_files_next(chan))
252                         f = ast_readframe(chan->stream);
253         }
254
255         return f;
256 }
257
258 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
259 {
260         struct moh_files_state *state = chan->music_state;
261         struct ast_frame *f = NULL;
262         int res = 0;
263
264         state->sample_queue += samples;
265
266         while (state->sample_queue > 0) {
267                 if ((f = moh_files_readframe(chan))) {
268                         state->samples += f->samples;
269                         res = ast_write(chan, f);
270                         state->sample_queue -= f->samples;
271                         ast_frfree(f);
272                         if (res < 0) {
273                                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
274                                 return -1;
275                         }
276                 } else
277                         return -1;      
278         }
279         return res;
280 }
281
282
283 static void *moh_files_alloc(struct ast_channel *chan, void *params)
284 {
285         struct moh_files_state *state;
286         struct mohclass *class = params;
287
288         if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
289                 chan->music_state = state;
290                 state->class = class;
291         } else 
292                 state = chan->music_state;
293
294         if (state) {
295                 if (state->class != class) {
296                         /* initialize */
297                         memset(state, 0, sizeof(*state));
298                         state->class = class;
299                 }
300
301                 state->origwfmt = chan->writeformat;
302
303                 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
304                         ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
305                         free(chan->music_state);
306                         chan->music_state = NULL;
307                 } else {
308                         if (option_verbose > 2)
309                                 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name);
310                 }
311         }
312         
313         return chan->music_state;
314 }
315
316 static struct ast_generator moh_file_stream = 
317 {
318         alloc: moh_files_alloc,
319         release: moh_files_release,
320         generate: moh_files_generator,
321 };
322
323 static int spawn_mp3(struct mohclass *class)
324 {
325         int fds[2];
326         int files = 0;
327         char fns[MAX_MP3S][80];
328         char *argv[MAX_MP3S + 50];
329         char xargs[256];
330         char *argptr;
331         int argc = 0;
332         DIR *dir = NULL;
333         struct dirent *de;
334
335         
336         if (!strcasecmp(class->dir, "nodir")) {
337                 files = 1;
338         } else {
339                 dir = opendir(class->dir);
340                 if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
341                         ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
342                         return -1;
343                 }
344         }
345
346         if (!ast_test_flag(class, MOH_CUSTOM)) {
347                 argv[argc++] = "mpg123";
348                 argv[argc++] = "-q";
349                 argv[argc++] = "-s";
350                 argv[argc++] = "--mono";
351                 argv[argc++] = "-r";
352                 argv[argc++] = "8000";
353                 
354                 if (!ast_test_flag(class, MOH_SINGLE)) {
355                         argv[argc++] = "-b";
356                         argv[argc++] = "2048";
357                 }
358                 
359                 argv[argc++] = "-f";
360                 
361                 if (ast_test_flag(class, MOH_QUIET))
362                         argv[argc++] = "4096";
363                 else
364                         argv[argc++] = "8192";
365                 
366                 /* Look for extra arguments and add them to the list */
367                 strncpy(xargs, class->args, sizeof(xargs) - 1);
368                 argptr = xargs;
369                 while (!ast_strlen_zero(argptr)) {
370                         argv[argc++] = argptr;
371                         argptr = strchr(argptr, ',');
372                         if (argptr) {
373                                 *argptr = '\0';
374                                 argptr++;
375                         }
376                 }
377         } else  {
378                 /* Format arguments for argv vector */
379                 strncpy(xargs, class->args, sizeof(xargs) - 1);
380                 argptr = xargs;
381                 while (!ast_strlen_zero(argptr)) {
382                         argv[argc++] = argptr;
383                         argptr = strchr(argptr, ' ');
384                         if (argptr) {
385                                 *argptr = '\0';
386                                 argptr++;
387                         }
388                 }
389         }
390
391
392         if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
393                 strncpy(fns[files], class->dir, sizeof(fns[files]) - 1);
394                 argv[argc++] = fns[files];
395                 files++;
396         } else if (dir) {
397                 while ((de = readdir(dir)) && (files < MAX_MP3S)) {
398                         if ((strlen(de->d_name) > 3) && 
399                             ((ast_test_flag(class, MOH_CUSTOM) && 
400                               (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
401                                !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
402                              !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
403                                 strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1);
404                                 argv[argc++] = fns[files];
405                                 files++;
406                         }
407                 }
408         }
409         argv[argc] = NULL;
410         if (dir) {
411                 closedir(dir);
412         }
413         if (pipe(fds)) {        
414                 ast_log(LOG_WARNING, "Pipe failed\n");
415                 return -1;
416         }
417 #if 0
418         printf("%d files total, %d args total\n", files, argc);
419         {
420                 int x;
421                 for (x=0;argv[x];x++)
422                         printf("arg%d: %s\n", x, argv[x]);
423         }
424 #endif  
425         if (!files) {
426                 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
427                 close(fds[0]);
428                 close(fds[1]);
429                 return -1;
430         }
431         if (time(NULL) - class->start < respawn_time) {
432                 sleep(respawn_time - (time(NULL) - class->start));
433         }
434         time(&class->start);
435         class->pid = fork();
436         if (class->pid < 0) {
437                 close(fds[0]);
438                 close(fds[1]);
439                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
440                 return -1;
441         }
442         if (!class->pid) {
443                 int x;
444                 close(fds[0]);
445                 /* Stdout goes to pipe */
446                 dup2(fds[1], STDOUT_FILENO);
447                 /* Close unused file descriptors */
448                 for (x=3;x<8192;x++) {
449                         if (-1 != fcntl(x, F_GETFL)) {
450                                 close(x);
451                         }
452                 }
453                 /* Child */
454                 chdir(class->dir);
455                 if (ast_test_flag(class, MOH_CUSTOM)) {
456                         execv(argv[0], argv);
457                 } else {
458                         /* Default install is /usr/local/bin */
459                         execv(LOCAL_MPG_123, argv);
460                         /* Many places have it in /usr/bin */
461                         execv(MPG_123, argv);
462                         /* Check PATH as a last-ditch effort */
463                         execvp("mpg123", argv);
464                 }
465                 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
466                 close(fds[1]);
467                 exit(1);
468         } else {
469                 /* Parent */
470                 close(fds[1]);
471         }
472         return fds[0];
473 }
474
475 static void *monmp3thread(void *data)
476 {
477 #define MOH_MS_INTERVAL         100
478
479         struct mohclass *class = data;
480         struct mohdata *moh;
481         char buf[8192];
482         short sbuf[8192];
483         int res, res2;
484         int len;
485         struct timeval tv, tv_tmp;
486
487         tv.tv_sec = 0;
488         tv.tv_usec = 0;
489         for(;/* ever */;) {
490                 pthread_testcancel();
491                 /* Spawn mp3 player if it's not there */
492                 if (class->srcfd < 0) {
493                         if ((class->srcfd = spawn_mp3(class)) < 0) {
494                                 ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
495                                 /* Try again later */
496                                 sleep(500);
497                                 pthread_testcancel();
498                         }
499                 }
500                 if (class->pseudofd > -1) {
501                         /* Pause some amount of time */
502                         res = read(class->pseudofd, buf, sizeof(buf));
503                         pthread_testcancel();
504                 } else {
505                         long delta;
506                         /* Reliable sleep */
507                         tv_tmp = ast_tvnow();
508                         if (ast_tvzero(tv))
509                                 tv = tv_tmp;
510                         delta = ast_tvdiff_ms(tv_tmp, tv);
511                         if (delta < MOH_MS_INTERVAL) {  /* too early */
512                                 tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */
513                                 usleep(1000 * (MOH_MS_INTERVAL - delta));
514                                 pthread_testcancel();
515                         } else {
516                                 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
517                                 tv = tv_tmp;
518                         }
519                         res = 8 * MOH_MS_INTERVAL;      /* 8 samples per millisecond */
520                 }
521                 if (!class->members)
522                         continue;
523                 /* Read mp3 audio */
524                 len = ast_codec_get_len(class->format, res);
525                 
526                 if ((res2 = read(class->srcfd, sbuf, len)) != len) {
527                         if (!res2) {
528                                 close(class->srcfd);
529                                 class->srcfd = -1;
530                                 pthread_testcancel();
531                                 if (class->pid) {
532                                         kill(class->pid, SIGHUP);
533                                         usleep(100000);
534                                         kill(class->pid, SIGTERM);
535                                         usleep(100000);
536                                         kill(class->pid, SIGKILL);
537                                         class->pid = 0;
538                                 }
539                         } else
540                                 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, len);
541                         continue;
542                 }
543                 pthread_testcancel();
544                 ast_mutex_lock(&moh_lock);
545                 moh = class->members;
546                 while (moh) {
547                         /* Write data */
548                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) 
549                                 if (option_debug)
550                                         ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
551                         moh = moh->next;
552                 }
553                 ast_mutex_unlock(&moh_lock);
554         }
555         return NULL;
556 }
557
558 static int moh0_exec(struct ast_channel *chan, void *data)
559 {
560         if (ast_moh_start(chan, data)) {
561                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
562                 return -1;
563         }
564         while (!ast_safe_sleep(chan, 10000));
565         ast_moh_stop(chan);
566         return -1;
567 }
568
569 static int moh1_exec(struct ast_channel *chan, void *data)
570 {
571         int res;
572         if (!data || !atoi(data)) {
573                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
574                 return -1;
575         }
576         if (ast_moh_start(chan, NULL)) {
577                 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
578                 return -1;
579         }
580         res = ast_safe_sleep(chan, atoi(data) * 1000);
581         ast_moh_stop(chan);
582         return res;
583 }
584
585 static int moh2_exec(struct ast_channel *chan, void *data)
586 {
587         if (ast_strlen_zero(data)) {
588                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
589                 return -1;
590         }
591         ast_string_field_set(chan, musicclass, data);
592         return 0;
593 }
594
595 static int moh3_exec(struct ast_channel *chan, void *data)
596 {
597         char *class = NULL;
598         if (data && strlen(data))
599                 class = data;
600         if (ast_moh_start(chan, class)) 
601                 ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
602
603         return 0;
604 }
605
606 static int moh4_exec(struct ast_channel *chan, void *data)
607 {
608         ast_moh_stop(chan);
609
610         return 0;
611 }
612
613 static struct mohclass *get_mohbyname(const char *name)
614 {
615         struct mohclass *moh;
616         moh = mohclasses;
617         while (moh) {
618                 if (!strcasecmp(name, moh->name))
619                         return moh;
620                 moh = moh->next;
621         }
622         return NULL;
623 }
624
625 static struct mohdata *mohalloc(struct mohclass *cl)
626 {
627         struct mohdata *moh;
628         long flags;     
629         if (!(moh = ast_calloc(1, sizeof(*moh))))
630                 return NULL;
631         if (pipe(moh->pipe)) {
632                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
633                 free(moh);
634                 return NULL;
635         }
636         /* Make entirely non-blocking */
637         flags = fcntl(moh->pipe[0], F_GETFL);
638         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
639         flags = fcntl(moh->pipe[1], F_GETFL);
640         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
641         moh->parent = cl;
642         moh->next = cl->members;
643         cl->members = moh;
644         return moh;
645 }
646
647 static void moh_release(struct ast_channel *chan, void *data)
648 {
649         struct mohdata *moh = data, *prev, *cur;
650         int oldwfmt;
651         ast_mutex_lock(&moh_lock);
652         /* Unlink */
653         prev = NULL;
654         cur = moh->parent->members;
655         while (cur) {
656                 if (cur == moh) {
657                         if (prev)
658                                 prev->next = cur->next;
659                         else
660                                 moh->parent->members = cur->next;
661                         break;
662                 }
663                 prev = cur;
664                 cur = cur->next;
665         }
666         ast_mutex_unlock(&moh_lock);
667         close(moh->pipe[0]);
668         close(moh->pipe[1]);
669         oldwfmt = moh->origwfmt;
670         free(moh);
671         if (chan) {
672                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
673                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
674                 if (option_verbose > 2)
675                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
676         }
677 }
678
679 static void *moh_alloc(struct ast_channel *chan, void *params)
680 {
681         struct mohdata *res;
682         struct mohclass *class = params;
683
684         if ((res = mohalloc(class))) {
685                 res->origwfmt = chan->writeformat;
686                 if (ast_set_write_format(chan, class->format)) {
687                         ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
688                         moh_release(NULL, res);
689                         res = NULL;
690                 }
691                 if (option_verbose > 2)
692                         ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
693         }
694         return res;
695 }
696
697 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
698 {
699         struct ast_frame f;
700         struct mohdata *moh = data;
701         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
702         int res;
703
704         if (!moh->parent->pid)
705                 return -1;
706
707         len = ast_codec_get_len(moh->parent->format, samples);
708
709         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
710                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
711                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
712         }
713         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
714 #if 0
715         if (res != len) {
716                 ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
717         }
718 #endif
719         if (res <= 0)
720                 return 0;
721
722         memset(&f, 0, sizeof(f));
723         
724         f.frametype = AST_FRAME_VOICE;
725         f.subclass = moh->parent->format;
726         f.mallocd = 0;
727         f.datalen = res;
728         f.data = buf + AST_FRIENDLY_OFFSET / 2;
729         f.offset = AST_FRIENDLY_OFFSET;
730         f.samples = ast_codec_get_samples(&f);
731
732         if (ast_write(chan, &f) < 0) {
733                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
734                 return -1;
735         }
736
737         return 0;
738 }
739
740 static struct ast_generator mohgen = 
741 {
742         alloc: moh_alloc,
743         release: moh_release,
744         generate: moh_generate,
745 };
746
747 static int moh_scan_files(struct mohclass *class) {
748
749         DIR *files_DIR;
750         struct dirent *files_dirent;
751         char path[512];
752         char filepath[MAX_MOHFILE_LEN];
753         char *ext;
754         struct stat statbuf;
755         int dirnamelen;
756         int i;
757         
758         files_DIR = opendir(class->dir);
759         if (!files_DIR) {
760                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
761                 return -1;
762         }
763
764         class->total_files = 0;
765         dirnamelen = strlen(class->dir) + 2;
766         getcwd(path, 512);
767         chdir(class->dir);
768         memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
769         while ((files_dirent = readdir(files_DIR))) {
770                 if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
771                         continue;
772
773                 snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
774
775                 if (stat(filepath, &statbuf))
776                         continue;
777
778                 if (!S_ISREG(statbuf.st_mode))
779                         continue;
780
781                 if ((ext = strrchr(filepath, '.'))) {
782                         *ext = '\0';
783                         ext++;
784                 }
785
786                 /* if the file is present in multiple formats, ensure we only put it into the list once */
787                 for (i = 0; i < class->total_files; i++)
788                         if (!strcmp(filepath, class->filearray[i]))
789                                 break;
790
791                 if (i == class->total_files)
792                         strcpy(class->filearray[class->total_files++], filepath);
793
794                 /* If the new total files is equal to the maximum allowed, stop adding new ones */
795                 if (class->total_files == MAX_MOHFILES)
796                         break;
797
798         }
799
800         closedir(files_DIR);
801         chdir(path);
802         return class->total_files;
803 }
804
805 static int moh_register(struct mohclass *moh, int reload)
806 {
807 #ifdef ZAPATA_MOH
808         int x;
809 #endif
810         ast_mutex_lock(&moh_lock);
811         if (get_mohbyname(moh->name)) {
812                 if (reload) {
813                         ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
814                 } else {
815                         ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
816                 }
817                 free(moh);      
818                 ast_mutex_unlock(&moh_lock);
819                 return -1;
820         }
821         ast_mutex_unlock(&moh_lock);
822
823         time(&moh->start);
824         moh->start -= respawn_time;
825         
826         if (!strcasecmp(moh->mode, "files")) {
827                 if (!moh_scan_files(moh)) {
828                         ast_moh_free_class(&moh);
829                         return -1;
830                 }
831                 if (strchr(moh->args, 'r'))
832                         ast_set_flag(moh, MOH_RANDOMIZE);
833         } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
834
835                 if (!strcasecmp(moh->mode, "custom"))
836                         ast_set_flag(moh, MOH_CUSTOM);
837                 else if (!strcasecmp(moh->mode, "mp3nb"))
838                         ast_set_flag(moh, MOH_SINGLE);
839                 else if (!strcasecmp(moh->mode, "quietmp3nb"))
840                         ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
841                 else if (!strcasecmp(moh->mode, "quietmp3"))
842                         ast_set_flag(moh, MOH_QUIET);
843                 
844                 moh->srcfd = -1;
845 #ifdef ZAPATA_MOH
846                 /* Open /dev/zap/pseudo for timing...  Is
847                    there a better, yet reliable way to do this? */
848                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
849                 if (moh->pseudofd < 0) {
850                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
851                 } else {
852                         x = 320;
853                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
854                 }
855 #else
856                 moh->pseudofd = -1;
857 #endif
858                 if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
859                         ast_log(LOG_WARNING, "Unable to create moh...\n");
860                         if (moh->pseudofd > -1)
861                                 close(moh->pseudofd);
862                         ast_moh_free_class(&moh);
863                         return -1;
864                 }
865         } else {
866                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
867                 ast_moh_free_class(&moh);
868                 return -1;
869         }
870         ast_mutex_lock(&moh_lock);
871         moh->next = mohclasses;
872         mohclasses = moh;
873         ast_mutex_unlock(&moh_lock);
874         return 0;
875 }
876
877 static void local_ast_moh_cleanup(struct ast_channel *chan)
878 {
879         if (chan->music_state) {
880                 free(chan->music_state);
881                 chan->music_state = NULL;
882         }
883 }
884
885 static int local_ast_moh_start(struct ast_channel *chan, const char *class)
886 {
887         struct mohclass *mohclass;
888
889         if (ast_strlen_zero(class))
890                 class = chan->musicclass;
891         if (ast_strlen_zero(class))
892                 class = "default";
893         ast_mutex_lock(&moh_lock);
894         mohclass = get_mohbyname(class);
895         ast_mutex_unlock(&moh_lock);
896
897         if (!mohclass) {
898                 ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
899                 return -1;
900         }
901
902         ast_set_flag(chan, AST_FLAG_MOH);
903         if (mohclass->total_files) {
904                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
905         } else
906                 return ast_activate_generator(chan, &mohgen, mohclass);
907 }
908
909 static void local_ast_moh_stop(struct ast_channel *chan)
910 {
911         ast_clear_flag(chan, AST_FLAG_MOH);
912         ast_deactivate_generator(chan);
913
914         if (chan->music_state) {
915                 if (chan->stream) {
916                         ast_closestream(chan->stream);
917                         chan->stream = NULL;
918                 }
919         }
920 }
921
922 static struct mohclass *moh_class_malloc(void)
923 {
924         struct mohclass *class;
925
926         if ((class = ast_calloc(1, sizeof(*class))))            
927                 class->format = AST_FORMAT_SLINEAR;
928
929         return class;
930 }
931
932 static int load_moh_classes(int reload)
933 {
934         struct ast_config *cfg;
935         struct ast_variable *var;
936         struct mohclass *class; 
937         char *data;
938         char *args;
939         char *cat;
940         int numclasses = 0;
941         static int dep_warning = 0;
942
943         cfg = ast_config_load("musiconhold.conf");
944
945         if (!cfg)
946                 return 0;
947
948         cat = ast_category_browse(cfg, NULL);
949         for (; cat; cat = ast_category_browse(cfg, cat)) {
950                 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {                       
951                         if (!(class = moh_class_malloc())) {
952                                 break;
953                         }                               
954                         ast_copy_string(class->name, cat, sizeof(class->name)); 
955                         var = ast_variable_browse(cfg, cat);
956                         while (var) {
957                                 if (!strcasecmp(var->name, "mode"))
958                                         ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
959                                 else if (!strcasecmp(var->name, "directory"))
960                                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
961                                 else if (!strcasecmp(var->name, "application"))
962                                         ast_copy_string(class->args, var->value, sizeof(class->args));
963                                 else if (!strcasecmp(var->name, "random"))
964                                         ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
965                                 else if (!strcasecmp(var->name, "format")) {
966                                         class->format = ast_getformatbyname(var->value);
967                                         if (!class->format) {
968                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
969                                                 class->format = AST_FORMAT_SLINEAR;
970                                         }
971                                 }
972                                 var = var->next;
973                         }
974
975                         if (ast_strlen_zero(class->dir)) {
976                                 if (!strcasecmp(class->mode, "custom")) {
977                                         strcpy(class->dir, "nodir");
978                                 } else {
979                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
980                                         free(class);
981                                         continue;
982                                 }
983                         }
984                         if (ast_strlen_zero(class->mode)) {
985                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
986                                 free(class);
987                                 continue;
988                         }
989                         if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
990                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
991                                 free(class);
992                                 continue;
993                         }
994
995                         /* Don't leak a class when it's already registered */
996                         moh_register(class, reload);
997
998                         numclasses++;
999                 }
1000         }
1001         
1002
1003         /* Deprecated Old-School Configuration */
1004         var = ast_variable_browse(cfg, "classes");
1005         while (var) {
1006                 if (!dep_warning) {
1007                         ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated!  Please refer to the sample configuration for information on the new syntax.\n");
1008                         dep_warning = 1;
1009                 }
1010                 data = strchr(var->value, ':');
1011                 if (data) {
1012                         *data++ = '\0';
1013                         args = strchr(data, ',');
1014                         if (args)
1015                                 *args++ = '\0';
1016                         if (!(get_mohbyname(var->name))) {                      
1017                                 if (!(class = moh_class_malloc())) {
1018                                         return numclasses;
1019                                 }
1020                                 
1021                                 ast_copy_string(class->name, var->name, sizeof(class->name));
1022                                 ast_copy_string(class->dir, data, sizeof(class->dir));
1023                                 ast_copy_string(class->mode, var->value, sizeof(class->mode));
1024                                 if (args)
1025                                         ast_copy_string(class->args, args, sizeof(class->args));
1026                                 
1027                                 moh_register(class, reload);
1028                                 numclasses++;
1029                         }
1030                 }
1031                 var = var->next;
1032         }
1033         var = ast_variable_browse(cfg, "moh_files");
1034         while (var) {
1035                 if (!dep_warning) {
1036                         ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated!  Please refer to the sample configuration for information on the new syntax.\n");
1037                         dep_warning = 1;
1038                 }
1039                 if (!(get_mohbyname(var->name))) {
1040                         args = strchr(var->value, ',');
1041                         if (args)
1042                                 *args++ = '\0';                 
1043                         if (!(class = moh_class_malloc())) {
1044                                 return numclasses;
1045                         }
1046                         
1047                         ast_copy_string(class->name, var->name, sizeof(class->name));
1048                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
1049                         strcpy(class->mode, "files");
1050                         if (args)       
1051                                 ast_copy_string(class->args, args, sizeof(class->args));
1052                         
1053                         moh_register(class, reload);
1054                         numclasses++;
1055                 }
1056                 var = var->next;
1057         }
1058
1059         ast_config_destroy(cfg);
1060
1061         return numclasses;
1062 }
1063
1064 static void ast_moh_destroy(void)
1065 {
1066         struct mohclass *moh, *tmp;
1067         char buff[8192];
1068         int bytes, tbytes=0, stime = 0, pid = 0;
1069
1070         if (option_verbose > 1)
1071                 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
1072         ast_mutex_lock(&moh_lock);
1073         moh = mohclasses;
1074
1075         while (moh) {
1076                 if (moh->pid) {
1077                         ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
1078                         stime = time(NULL) + 2;
1079                         pid = moh->pid;
1080                         moh->pid = 0;
1081                         /* Back when this was just mpg123, SIGKILL was fine.  Now we need
1082                          * to give the process a reason and time enough to kill off its
1083                          * children. */
1084                         kill(pid, SIGHUP);
1085                         usleep(100000);
1086                         kill(pid, SIGTERM);
1087                         usleep(100000);
1088                         kill(pid, SIGKILL);
1089                         while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) {
1090                                 tbytes = tbytes + bytes;
1091                         }
1092                         ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1093                         close(moh->srcfd);
1094                 }
1095                 tmp = moh;
1096                 moh = moh->next;
1097                 ast_moh_free_class(&tmp);
1098         }
1099         mohclasses = NULL;
1100         ast_mutex_unlock(&moh_lock);
1101 }
1102
1103 static void moh_on_off(int on)
1104 {
1105         struct ast_channel *chan = NULL;
1106
1107         while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
1108                 if (ast_test_flag(chan, AST_FLAG_MOH)) {
1109                         if (on)
1110                                 local_ast_moh_start(chan, NULL);
1111                         else
1112                                 ast_deactivate_generator(chan);
1113                 }
1114                 ast_mutex_unlock(&chan->lock);
1115         }
1116 }
1117
1118 static int moh_cli(int fd, int argc, char *argv[]) 
1119 {
1120         int x;
1121
1122         moh_on_off(0);
1123         ast_moh_destroy();
1124         x = load_moh_classes(1);
1125         moh_on_off(1);
1126         ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
1127         return 0;
1128 }
1129
1130 static int cli_files_show(int fd, int argc, char *argv[])
1131 {
1132         int i;
1133         struct mohclass *class;
1134
1135         ast_mutex_lock(&moh_lock);
1136         for (class = mohclasses; class; class = class->next) {
1137                 if (!class->total_files)
1138                         continue;
1139
1140                 ast_cli(fd, "Class: %s\n", class->name);
1141                 for (i = 0; i < class->total_files; i++)
1142                         ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
1143         }
1144         ast_mutex_unlock(&moh_lock);
1145
1146         return 0;
1147 }
1148
1149 static int moh_classes_show(int fd, int argc, char *argv[])
1150 {
1151         struct mohclass *class;
1152
1153         ast_mutex_lock(&moh_lock);
1154         for (class = mohclasses; class; class = class->next) {
1155                 ast_cli(fd, "Class: %s\n", class->name);
1156                 ast_cli(fd, "\tMode: %s\n", S_OR(class->mode,"<none>"));
1157                 ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1158                 if (ast_test_flag(class, MOH_CUSTOM))
1159                         ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1160                 ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
1161         }
1162         ast_mutex_unlock(&moh_lock);
1163
1164         return 0;
1165 }
1166
1167 static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
1168
1169 static struct ast_cli_entry  cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL};
1170
1171 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};
1172
1173 static int init_classes(int reload) 
1174 {
1175         struct mohclass *moh;
1176     
1177         if (!load_moh_classes(reload))          /* Load classes from config */
1178                 return 0;                       /* Return if nothing is found */
1179         moh = mohclasses;
1180         while (moh) {
1181                 if (moh->total_files)
1182                         moh_scan_files(moh);
1183                 moh = moh->next;
1184         }
1185         return 1;
1186 }
1187
1188 static int load_module(void *mod)
1189 {
1190         int res;
1191
1192         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
1193         ast_register_atexit(ast_moh_destroy);
1194         ast_cli_register(&cli_moh);
1195         ast_cli_register(&cli_moh_files_show);
1196         ast_cli_register(&cli_moh_classes_show);
1197         if (!res)
1198                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
1199         if (!res)
1200                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
1201         if (!res)
1202                 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
1203         if (!res)
1204                 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
1205
1206         if (!init_classes(0)) {         /* No music classes configured, so skip it */
1207                 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.");
1208         } else {
1209                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1210         }
1211
1212         return 0;
1213 }
1214
1215 static int reload(void *mod)
1216 {
1217         if (init_classes(1))
1218                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1219
1220         return 0;
1221 }
1222
1223 static int unload_module(void *mod)
1224 {
1225         return -1;
1226 }
1227
1228 static const char *description(void)
1229 {
1230         return "Music On Hold Resource";
1231 }
1232
1233 static const char *key(void)
1234 {
1235         return ASTERISK_GPL_KEY;
1236 }
1237
1238 STD_MOD(MOD_0 | NO_USECOUNT | NO_UNLOAD, reload, NULL, NULL);