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