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