8647316d2347f48abe190c814ab2d66e3459f76d
[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>dahdi</use>
31  ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include <ctype.h>
38 #include <signal.h>
39 #include <sys/time.h>
40 #include <sys/signal.h>
41 #include <netinet/in.h>
42 #include <sys/stat.h>
43 #include <dirent.h>
44 #include <sys/ioctl.h>
45 #ifdef SOLARIS
46 #include <thread.h>
47 #endif
48
49 #ifdef HAVE_DAHDI
50 #include <dahdi/user.h>
51 #endif
52
53 #include "asterisk/lock.h"
54 #include "asterisk/file.h"
55 #include "asterisk/channel.h"
56 #include "asterisk/pbx.h"
57 #include "asterisk/app.h"
58 #include "asterisk/module.h"
59 #include "asterisk/translate.h"
60 #include "asterisk/say.h"
61 #include "asterisk/musiconhold.h"
62 #include "asterisk/config.h"
63 #include "asterisk/utils.h"
64 #include "asterisk/cli.h"
65 #include "asterisk/stringfields.h"
66 #include "asterisk/linkedlists.h"
67 #include "asterisk/manager.h"
68 #include "asterisk/paths.h"
69 #include "asterisk/astobj2.h"
70
71 #define INITIAL_NUM_FILES   8
72
73 /*** DOCUMENTATION
74         <application name="MusicOnHold" language="en_US">
75                 <synopsis>
76                         Play Music On Hold indefinitely.
77                 </synopsis>
78                 <syntax>
79                         <parameter name="class" required="true" />
80                         <parameter name="duration" />
81                 </syntax>
82                 <description>
83                         <para>Plays hold music specified by class. If omitted, the default music
84                         source for the channel will be used. Change the default class with
85                         Set(CHANNEL(musicclass)=...). If duration is given, hold music will be played
86                         specified number of seconds. If duration is ommited, music plays indefinitely.
87                         Returns <literal>0</literal> when done, <literal>-1</literal> on hangup.</para>
88                 </description>
89         </application>
90         <application name="WaitMusicOnHold" language="en_US">
91                 <synopsis>
92                         Wait, playing Music On Hold.
93                 </synopsis>
94                 <syntax>
95                         <parameter name="delay" required="true" />
96                 </syntax>
97                 <description>
98                         <para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
99                         <para>Plays hold music specified number of seconds. Returns <literal>0</literal> when done,
100                         or <literal>-1</literal> on hangup. If no hold music is available, the delay will still occur
101                         with no sound.</para>
102                         <para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
103                 </description>
104         </application>
105         <application name="SetMusicOnHold" language="en_US">
106                 <synopsis>
107                         Set default Music On Hold class.
108                 </synopsis>
109                 <syntax>
110                         <parameter name="class" required="yes" />
111                 </syntax>
112                 <description>
113                         <para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
114                         <para>Sets the default class for music on hold for a given channel.
115                         When music on hold is activated, this class will be used to select which
116                         music is played.</para>
117                         <para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
118                 </description>
119         </application>
120         <application name="StartMusicOnHold" language="en_US">
121                 <synopsis>
122                         Play Music On Hold.
123                 </synopsis>
124                 <syntax>
125                         <parameter name="class" required="true" />
126                 </syntax>
127                 <description>
128                         <para>Starts playing music on hold, uses default music class for channel.
129                         Starts playing music specified by class. If omitted, the default music
130                         source for the channel will be used. Always returns <literal>0</literal>.</para>
131                 </description>
132         </application>
133         <application name="StopMusicOnHold" language="en_US">
134                 <synopsis>
135                         Stop playing Music On Hold.
136                 </synopsis>
137                 <syntax />
138                 <description>
139                         <para>Stops playing music on hold.</para>
140                 </description>
141         </application>
142  ***/
143
144 static const char play_moh[] = "MusicOnHold";
145 static const char wait_moh[] = "WaitMusicOnHold";
146 static const char set_moh[] = "SetMusicOnHold";
147 static const char start_moh[] = "StartMusicOnHold";
148 static const char stop_moh[] = "StopMusicOnHold";
149
150 static int respawn_time = 20;
151
152 struct moh_files_state {
153         struct mohclass *class;
154         int origwfmt;
155         int samples;
156         int sample_queue;
157         int pos;
158         int save_pos;
159         char *save_pos_filename;
160 };
161
162 #define MOH_QUIET               (1 << 0)
163 #define MOH_SINGLE              (1 << 1)
164 #define MOH_CUSTOM              (1 << 2)
165 #define MOH_RANDOMIZE           (1 << 3)
166 #define MOH_SORTALPHA           (1 << 4)
167
168 #define MOH_CACHERTCLASSES      (1 << 5)        /*!< Should we use a separate instance of MOH for each user or not */
169
170 static struct ast_flags global_flags[1] = {{0}};        /*!< global MOH_ flags */
171
172 struct mohclass {
173         char name[MAX_MUSICCLASS];
174         char dir[256];
175         char args[256];
176         char mode[80];
177         char digit;
178         /*! A dynamically sized array to hold the list of filenames in "files" mode */
179         char **filearray;
180         /*! The current size of the filearray */
181         int allowed_files;
182         /*! The current number of files loaded into the filearray */
183         int total_files;
184         unsigned int flags;
185         /*! The format from the MOH source, not applicable to "files" mode */
186         int format;
187         /*! The pid of the external application delivering MOH */
188         int pid;
189         time_t start;
190         pthread_t thread;
191         /*! Source of audio */
192         int srcfd;
193         /*! FD for timing source */
194         int pseudofd;
195         /*! Created on the fly, from RT engine */
196         int realtime;
197         unsigned int delete:1;
198         AST_LIST_HEAD_NOLOCK(, mohdata) members;
199         AST_LIST_ENTRY(mohclass) list;
200 };
201
202 struct mohdata {
203         int pipe[2];
204         int origwfmt;
205         struct mohclass *parent;
206         struct ast_frame f;
207         AST_LIST_ENTRY(mohdata) list;
208 };
209
210 static struct ao2_container *mohclasses;
211
212 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
213 #define MPG_123 "/usr/bin/mpg123"
214 #define MAX_MP3S 256
215
216 static int reload(void);
217
218 #define mohclass_ref(class,string)   (ao2_t_ref((class), +1, (string)), class)
219 #define mohclass_unref(class,string) (ao2_t_ref((class), -1, (string)), (struct mohclass *) NULL)
220
221 static void moh_files_release(struct ast_channel *chan, void *data)
222 {
223         struct moh_files_state *state;
224
225         if (!chan || !chan->music_state) {
226                 return;
227         }
228
229         state = chan->music_state;
230
231         if (chan->stream) {
232                 ast_closestream(chan->stream);
233                 chan->stream = NULL;
234         }
235         
236         if (option_verbose > 2) {
237                 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
238         }
239
240         if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
241                 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
242         }
243
244         state->save_pos = state->pos;
245
246         mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
247 }
248
249 static int ast_moh_files_next(struct ast_channel *chan) 
250 {
251         struct moh_files_state *state = chan->music_state;
252         int tries;
253
254         /* Discontinue a stream if it is running already */
255         if (chan->stream) {
256                 ast_closestream(chan->stream);
257                 chan->stream = NULL;
258         }
259
260         if (!state->class->total_files) {
261                 ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name);
262                 return -1;
263         }
264
265         /* If a specific file has been saved confirm it still exists and that it is still valid */
266         if (state->save_pos >= 0 && state->save_pos < state->class->total_files && state->class->filearray[state->save_pos] == state->save_pos_filename) {
267                 state->pos = state->save_pos;
268                 state->save_pos = -1;
269         } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) {
270                 /* Get a random file and ensure we can open it */
271                 for (tries = 0; tries < 20; tries++) {
272                         state->pos = ast_random() % state->class->total_files;
273                         if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0)
274                                 break;
275                 }
276                 state->save_pos = -1;
277                 state->samples = 0;
278         } else {
279                 /* This is easy, just increment our position and make sure we don't exceed the total file count */
280                 state->pos++;
281                 state->pos %= state->class->total_files;
282                 state->save_pos = -1;
283                 state->samples = 0;
284         }
285
286         if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
287                 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
288                 state->pos++;
289                 state->pos %= state->class->total_files;
290                 return -1;
291         }
292
293         /* Record the pointer to the filename for position resuming later */
294         state->save_pos_filename = state->class->filearray[state->pos];
295
296         ast_debug(1, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
297
298         if (state->samples)
299                 ast_seekstream(chan->stream, state->samples, SEEK_SET);
300
301         return 0;
302 }
303
304 static struct ast_frame *moh_files_readframe(struct ast_channel *chan) 
305 {
306         struct ast_frame *f = NULL;
307         
308         if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
309                 if (!ast_moh_files_next(chan))
310                         f = ast_readframe(chan->stream);
311         }
312
313         return f;
314 }
315
316 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
317 {
318         struct moh_files_state *state = chan->music_state;
319         struct ast_frame *f = NULL;
320         int res = 0;
321
322         state->sample_queue += samples;
323
324         while (state->sample_queue > 0) {
325                 if ((f = moh_files_readframe(chan))) {
326                         state->samples += f->samples;
327                         state->sample_queue -= f->samples;
328                         res = ast_write(chan, f);
329                         ast_frfree(f);
330                         if (res < 0) {
331                                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
332                                 return -1;
333                         }
334                 } else
335                         return -1;      
336         }
337         return res;
338 }
339
340 static void *moh_files_alloc(struct ast_channel *chan, void *params)
341 {
342         struct moh_files_state *state;
343         struct mohclass *class = params;
344
345         if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
346                 chan->music_state = state;
347         } else {
348                 state = chan->music_state;
349         }
350
351         if (!state) {
352                 return NULL;
353         }
354
355         if (state->class != class) {
356                 memset(state, 0, sizeof(*state));
357                 if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) {
358                         state->pos = ast_random() % class->total_files;
359                 }
360         }
361
362         state->class = mohclass_ref(class, "Reffing music class for channel");
363         state->origwfmt = chan->writeformat;
364
365         ast_verb(3, "Started music on hold, class '%s', on %s\n", class->name, chan->name);
366         
367         return chan->music_state;
368 }
369
370 static int moh_digit_match(void *obj, void *arg, int flags)
371 {
372         char *digit = arg;
373         struct mohclass *class = obj;
374
375         return (*digit == class->digit) ? CMP_MATCH | CMP_STOP : 0;
376 }
377
378 /*! \note This function should be called with the mohclasses list locked */
379 static struct mohclass *get_mohbydigit(char digit)
380 {
381         return ao2_t_callback(mohclasses, 0, moh_digit_match, &digit, "digit callback");
382 }
383
384 static void moh_handle_digit(struct ast_channel *chan, char digit)
385 {
386         struct mohclass *class;
387         const char *classname = NULL;
388
389         if ((class = get_mohbydigit(digit))) {
390                 classname = ast_strdupa(class->name);
391                 class = mohclass_unref(class, "Unreffing ao2_find from finding by digit");
392         }
393
394         if (!class) {
395                 return;
396         }
397
398         ast_moh_stop(chan);
399         ast_moh_start(chan, classname, NULL);
400 }
401
402 static struct ast_generator moh_file_stream = 
403 {
404         .alloc    = moh_files_alloc,
405         .release  = moh_files_release,
406         .generate = moh_files_generator,
407         .digit    = moh_handle_digit,
408 };
409
410 static int spawn_mp3(struct mohclass *class)
411 {
412         int fds[2];
413         int files = 0;
414         char fns[MAX_MP3S][80];
415         char *argv[MAX_MP3S + 50];
416         char xargs[256];
417         char *argptr;
418         int argc = 0;
419         DIR *dir = NULL;
420         struct dirent *de;
421
422         
423         if (!strcasecmp(class->dir, "nodir")) {
424                 files = 1;
425         } else {
426                 dir = opendir(class->dir);
427                 if (!dir && strncasecmp(class->dir, "http://", 7)) {
428                         ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
429                         return -1;
430                 }
431         }
432
433         if (!ast_test_flag(class, MOH_CUSTOM)) {
434                 argv[argc++] = "mpg123";
435                 argv[argc++] = "-q";
436                 argv[argc++] = "-s";
437                 argv[argc++] = "--mono";
438                 argv[argc++] = "-r";
439                 argv[argc++] = "8000";
440                 
441                 if (!ast_test_flag(class, MOH_SINGLE)) {
442                         argv[argc++] = "-b";
443                         argv[argc++] = "2048";
444                 }
445                 
446                 argv[argc++] = "-f";
447                 
448                 if (ast_test_flag(class, MOH_QUIET))
449                         argv[argc++] = "4096";
450                 else
451                         argv[argc++] = "8192";
452                 
453                 /* Look for extra arguments and add them to the list */
454                 ast_copy_string(xargs, class->args, sizeof(xargs));
455                 argptr = xargs;
456                 while (!ast_strlen_zero(argptr)) {
457                         argv[argc++] = argptr;
458                         strsep(&argptr, ",");
459                 }
460         } else  {
461                 /* Format arguments for argv vector */
462                 ast_copy_string(xargs, class->args, sizeof(xargs));
463                 argptr = xargs;
464                 while (!ast_strlen_zero(argptr)) {
465                         argv[argc++] = argptr;
466                         strsep(&argptr, " ");
467                 }
468         }
469
470         if (!strncasecmp(class->dir, "http://", 7)) {
471                 ast_copy_string(fns[files], class->dir, sizeof(fns[files]));
472                 argv[argc++] = fns[files];
473                 files++;
474         } else if (dir) {
475                 while ((de = readdir(dir)) && (files < MAX_MP3S)) {
476                         if ((strlen(de->d_name) > 3) && 
477                             ((ast_test_flag(class, MOH_CUSTOM) && 
478                               (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
479                                !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
480                              !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
481                                 ast_copy_string(fns[files], de->d_name, sizeof(fns[files]));
482                                 argv[argc++] = fns[files];
483                                 files++;
484                         }
485                 }
486         }
487         argv[argc] = NULL;
488         if (dir) {
489                 closedir(dir);
490         }
491         if (pipe(fds)) {        
492                 ast_log(LOG_WARNING, "Pipe failed\n");
493                 return -1;
494         }
495         if (!files) {
496                 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
497                 close(fds[0]);
498                 close(fds[1]);
499                 return -1;
500         }
501         if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) {
502                 sleep(respawn_time - (time(NULL) - class->start));
503         }
504
505         time(&class->start);
506         class->pid = ast_safe_fork(0);
507         if (class->pid < 0) {
508                 close(fds[0]);
509                 close(fds[1]);
510                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
511                 return -1;
512         }
513         if (!class->pid) {
514                 if (ast_opt_high_priority)
515                         ast_set_priority(0);
516
517                 close(fds[0]);
518                 /* Stdout goes to pipe */
519                 dup2(fds[1], STDOUT_FILENO);
520
521                 /* Close everything else */
522                 ast_close_fds_above_n(STDERR_FILENO);
523
524                 /* Child */
525                 if (strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) {
526                         ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
527                         _exit(1);
528                 }
529                 setpgid(0, getpid());
530                 if (ast_test_flag(class, MOH_CUSTOM)) {
531                         execv(argv[0], argv);
532                 } else {
533                         /* Default install is /usr/local/bin */
534                         execv(LOCAL_MPG_123, argv);
535                         /* Many places have it in /usr/bin */
536                         execv(MPG_123, argv);
537                         /* Check PATH as a last-ditch effort */
538                         execvp("mpg123", argv);
539                 }
540                 /* Can't use logger, since log FDs are closed */
541                 fprintf(stderr, "MOH: exec failed: %s\n", strerror(errno));
542                 close(fds[1]);
543                 _exit(1);
544         } else {
545                 /* Parent */
546                 close(fds[1]);
547         }
548         return fds[0];
549 }
550
551 static void *monmp3thread(void *data)
552 {
553 #define MOH_MS_INTERVAL         100
554
555         struct mohclass *class = data;
556         struct mohdata *moh;
557         char buf[8192];
558         short sbuf[8192];
559         int res, res2;
560         int len;
561         struct timeval deadline, tv_tmp;
562
563         deadline.tv_sec = 0;
564         deadline.tv_usec = 0;
565         for(;/* ever */;) {
566                 pthread_testcancel();
567                 /* Spawn mp3 player if it's not there */
568                 if (class->srcfd < 0) {
569                         if ((class->srcfd = spawn_mp3(class)) < 0) {
570                                 ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
571                                 /* Try again later */
572                                 sleep(500);
573                                 pthread_testcancel();
574                         }
575                 }
576                 if (class->pseudofd > -1) {
577 #ifdef SOLARIS
578                         thr_yield();
579 #endif
580                         /* Pause some amount of time */
581                         res = read(class->pseudofd, buf, sizeof(buf));
582                         pthread_testcancel();
583                 } else {
584                         long delta;
585                         /* Reliable sleep */
586                         tv_tmp = ast_tvnow();
587                         if (ast_tvzero(deadline))
588                                 deadline = tv_tmp;
589                         delta = ast_tvdiff_ms(tv_tmp, deadline);
590                         if (delta < MOH_MS_INTERVAL) {  /* too early */
591                                 deadline = ast_tvadd(deadline, ast_samp2tv(MOH_MS_INTERVAL, 1000));     /* next deadline */
592                                 usleep(1000 * (MOH_MS_INTERVAL - delta));
593                                 pthread_testcancel();
594                         } else {
595                                 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
596                                 deadline = tv_tmp;
597                         }
598                         res = 8 * MOH_MS_INTERVAL;      /* 8 samples per millisecond */
599                 }
600                 if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members))
601                         continue;
602                 /* Read mp3 audio */
603                 len = ast_codec_get_len(class->format, res);
604
605                 if ((res2 = read(class->srcfd, sbuf, len)) != len) {
606                         if (!res2) {
607                                 close(class->srcfd);
608                                 class->srcfd = -1;
609                                 pthread_testcancel();
610                                 if (class->pid > 1) {
611                                         killpg(class->pid, SIGHUP);
612                                         usleep(100000);
613                                         killpg(class->pid, SIGTERM);
614                                         usleep(100000);
615                                         killpg(class->pid, SIGKILL);
616                                         class->pid = 0;
617                                 }
618                         } else {
619                                 ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len);
620                         }
621                         continue;
622                 }
623
624                 pthread_testcancel();
625
626                 ao2_lock(class);
627                 AST_LIST_TRAVERSE(&class->members, moh, list) {
628                         /* Write data */
629                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) {
630                                 ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2);
631                         }
632                 }
633                 ao2_unlock(class);
634         }
635         return NULL;
636 }
637
638 static int play_moh_exec(struct ast_channel *chan, const char *data)
639 {
640         char *parse;
641         char *class;
642         int timeout = -1;
643         int res;
644         AST_DECLARE_APP_ARGS(args,
645                 AST_APP_ARG(class);
646                 AST_APP_ARG(duration);
647         );
648
649         parse = ast_strdupa(data);
650
651         AST_STANDARD_APP_ARGS(args, parse);
652
653         if (!ast_strlen_zero(args.duration)) {
654                 if (sscanf(args.duration, "%d", &timeout) == 1) {
655                         timeout *= 1000;
656                 } else {
657                         ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration);
658                 }
659         }
660
661         class = S_OR(args.class, NULL);
662         if (ast_moh_start(chan, class, NULL)) {
663                 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name);
664                 return 0;
665         }
666
667         if (timeout > 0)
668                 res = ast_safe_sleep(chan, timeout);
669         else {
670                 while (!(res = ast_safe_sleep(chan, 10000)));
671         }
672
673         ast_moh_stop(chan);
674
675         return res;
676 }
677
678 static int wait_moh_exec(struct ast_channel *chan, const char *data)
679 {
680         static int deprecation_warning = 0;
681         int res;
682
683         if (!deprecation_warning) {
684                 deprecation_warning = 1;
685                 ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n");
686         }
687
688         if (!data || !atoi(data)) {
689                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
690                 return -1;
691         }
692         if (ast_moh_start(chan, NULL, NULL)) {
693                 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
694                 return 0;
695         }
696         res = ast_safe_sleep(chan, atoi(data) * 1000);
697         ast_moh_stop(chan);
698         return res;
699 }
700
701 static int set_moh_exec(struct ast_channel *chan, const char *data)
702 {
703         static int deprecation_warning = 0;
704
705         if (!deprecation_warning) {
706                 deprecation_warning = 1;
707                 ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n");
708         }
709
710         if (ast_strlen_zero(data)) {
711                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
712                 return -1;
713         }
714         ast_string_field_set(chan, musicclass, data);
715         return 0;
716 }
717
718 static int start_moh_exec(struct ast_channel *chan, const char *data)
719 {
720         char *parse;
721         char *class;
722         AST_DECLARE_APP_ARGS(args,
723                 AST_APP_ARG(class);
724         );
725
726         parse = ast_strdupa(data);
727
728         AST_STANDARD_APP_ARGS(args, parse);
729
730         class = S_OR(args.class, NULL);
731         if (ast_moh_start(chan, class, NULL)) 
732                 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name);
733
734         return 0;
735 }
736
737 static int stop_moh_exec(struct ast_channel *chan, const char *data)
738 {
739         ast_moh_stop(chan);
740
741         return 0;
742 }
743
744 static struct mohclass *get_mohbyname(const char *name, int warn)
745 {
746         struct mohclass *moh = NULL;
747         struct mohclass tmp_class = {
748                 .flags = 0,
749         };
750
751         ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name));
752
753         moh = ao2_t_find(mohclasses, &tmp_class, 0, "Finding by name");
754
755         if (!moh && warn) {
756                 ast_log(LOG_DEBUG, "Music on Hold class '%s' not found in memory\n", name);
757         }
758
759         return moh;
760 }
761
762 static struct mohdata *mohalloc(struct mohclass *cl)
763 {
764         struct mohdata *moh;
765         long flags;     
766         
767         if (!(moh = ast_calloc(1, sizeof(*moh))))
768                 return NULL;
769         
770         if (pipe(moh->pipe)) {
771                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
772                 ast_free(moh);
773                 return NULL;
774         }
775
776         /* Make entirely non-blocking */
777         flags = fcntl(moh->pipe[0], F_GETFL);
778         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
779         flags = fcntl(moh->pipe[1], F_GETFL);
780         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
781
782         moh->f.frametype = AST_FRAME_VOICE;
783         moh->f.subclass = cl->format;
784         moh->f.offset = AST_FRIENDLY_OFFSET;
785
786         moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent");
787
788         ao2_lock(cl);
789         AST_LIST_INSERT_HEAD(&cl->members, moh, list);
790         ao2_unlock(cl);
791         
792         return moh;
793 }
794
795 static void moh_release(struct ast_channel *chan, void *data)
796 {
797         struct mohdata *moh = data;
798         struct mohclass *class = moh->parent;
799         int oldwfmt;
800
801         ao2_lock(class);
802         AST_LIST_REMOVE(&moh->parent->members, moh, list);      
803         ao2_unlock(class);
804         
805         close(moh->pipe[0]);
806         close(moh->pipe[1]);
807
808         oldwfmt = moh->origwfmt;
809
810         moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator");
811
812         ast_free(moh);
813
814         if (chan) {
815                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) {
816                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n",
817                                         chan->name, ast_getformatname(oldwfmt));
818                 }
819
820                 ast_verb(3, "Stopped music on hold on %s\n", chan->name);
821         }
822 }
823
824 static void *moh_alloc(struct ast_channel *chan, void *params)
825 {
826         struct mohdata *res;
827         struct mohclass *class = params;
828         struct moh_files_state *state;
829
830         /* Initiating music_state for current channel. Channel should know name of moh class */
831         if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
832                 chan->music_state = state;
833                 state->class = class;
834         } else
835                 state = chan->music_state;
836         if (state && state->class != class) {
837                 memset(state, 0, sizeof(*state));
838                 state->class = class;
839         }
840
841         if ((res = mohalloc(class))) {
842                 res->origwfmt = chan->writeformat;
843                 if (ast_set_write_format(chan, class->format)) {
844                         ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
845                         moh_release(NULL, res);
846                         res = NULL;
847                 }
848                 ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
849         }
850         return res;
851 }
852
853 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
854 {
855         struct mohdata *moh = data;
856         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
857         int res;
858
859         len = ast_codec_get_len(moh->parent->format, samples);
860
861         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
862                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
863                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
864         }
865         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
866         if (res <= 0)
867                 return 0;
868
869         moh->f.datalen = res;
870         moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2;
871         moh->f.samples = ast_codec_get_samples(&moh->f);
872
873         if (ast_write(chan, &moh->f) < 0) {
874                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
875                 return -1;
876         }
877
878         return 0;
879 }
880
881 static struct ast_generator mohgen = {
882         .alloc    = moh_alloc,
883         .release  = moh_release,
884         .generate = moh_generate,
885         .digit    = moh_handle_digit,
886 };
887
888 static int moh_add_file(struct mohclass *class, const char *filepath)
889 {
890         if (!class->allowed_files) {
891                 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
892                         return -1;
893                 class->allowed_files = INITIAL_NUM_FILES;
894         } else if (class->total_files == class->allowed_files) {
895                 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
896                         class->allowed_files = 0;
897                         class->total_files = 0;
898                         return -1;
899                 }
900                 class->allowed_files *= 2;
901         }
902
903         if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
904                 return -1;
905
906         class->total_files++;
907
908         return 0;
909 }
910
911 static int moh_sort_compare(const void *i1, const void *i2)
912 {
913         char *s1, *s2;
914
915         s1 = ((char **)i1)[0];
916         s2 = ((char **)i2)[0];
917
918         return strcasecmp(s1, s2);
919 }
920
921 static int moh_scan_files(struct mohclass *class) {
922
923         DIR *files_DIR;
924         struct dirent *files_dirent;
925         char dir_path[PATH_MAX];
926         char path[PATH_MAX];
927         char filepath[PATH_MAX];
928         char *ext;
929         struct stat statbuf;
930         int dirnamelen;
931         int i;
932
933         if (class->dir[0] != '/') {
934                 ast_copy_string(dir_path, ast_config_AST_VAR_DIR, sizeof(dir_path));
935                 strncat(dir_path, "/", sizeof(dir_path) - 1);
936                 strncat(dir_path, class->dir, sizeof(dir_path) - 1);
937         } else {
938                 ast_copy_string(dir_path, class->dir, sizeof(dir_path));
939         }
940         ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
941         files_DIR = opendir(dir_path);
942         if (!files_DIR) {
943                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path);
944                 return -1;
945         }
946
947         for (i = 0; i < class->total_files; i++)
948                 ast_free(class->filearray[i]);
949
950         class->total_files = 0;
951         dirnamelen = strlen(dir_path) + 2;
952         if (!getcwd(path, sizeof(path))) {
953                 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno));
954                 return -1;
955         }
956         if (chdir(dir_path) < 0) {
957                 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
958                 return -1;
959         }
960         while ((files_dirent = readdir(files_DIR))) {
961                 /* The file name must be at least long enough to have the file type extension */
962                 if ((strlen(files_dirent->d_name) < 4))
963                         continue;
964
965                 /* Skip files that starts with a dot */
966                 if (files_dirent->d_name[0] == '.')
967                         continue;
968
969                 /* Skip files without extensions... they are not audio */
970                 if (!strchr(files_dirent->d_name, '.'))
971                         continue;
972
973                 snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name);
974
975                 if (stat(filepath, &statbuf))
976                         continue;
977
978                 if (!S_ISREG(statbuf.st_mode))
979                         continue;
980
981                 if ((ext = strrchr(filepath, '.')))
982                         *ext = '\0';
983
984                 /* if the file is present in multiple formats, ensure we only put it into the list once */
985                 for (i = 0; i < class->total_files; i++)
986                         if (!strcmp(filepath, class->filearray[i]))
987                                 break;
988
989                 if (i == class->total_files) {
990                         if (moh_add_file(class, filepath))
991                                 break;
992                 }
993         }
994
995         closedir(files_DIR);
996         if (chdir(path) < 0) {
997                 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
998                 return -1;
999         }
1000         if (ast_test_flag(class, MOH_SORTALPHA))
1001                 qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare);
1002         return class->total_files;
1003 }
1004
1005 static int init_files_class(struct mohclass *class)
1006 {
1007         int res;
1008
1009         res = moh_scan_files(class);
1010
1011         if (res < 0) {
1012                 return -1;
1013         }
1014
1015         if (!res) {
1016                 if (option_verbose > 2) {
1017                         ast_verbose(VERBOSE_PREFIX_3 "Files not found in %s for moh class:%s\n",
1018                                         class->dir, class->name);
1019                 }
1020                 return -1;
1021         }
1022
1023         if (strchr(class->args, 'r')) {
1024                 ast_set_flag(class, MOH_RANDOMIZE);
1025         }
1026
1027         return 0;
1028 }
1029
1030
1031 static int moh_diff(struct mohclass *old, struct mohclass *new)
1032 {
1033         if (!old || !new) {
1034                 return -1;
1035         }
1036
1037         if (strcmp(old->dir, new->dir)) {
1038                 return -1;
1039         } else if (strcmp(old->mode, new->mode)) {
1040                 return -1;
1041         } else if (strcmp(old->args, new->args)) {
1042                 return -1;
1043         } else if (old->flags != new->flags) {
1044                 return -1;
1045         }
1046
1047         return 0;
1048 }
1049
1050 static int init_app_class(struct mohclass *class)
1051 {
1052 #ifdef HAVE_DAHDI
1053         int x;
1054 #endif
1055
1056         if (!strcasecmp(class->mode, "custom")) {
1057                 ast_set_flag(class, MOH_CUSTOM);
1058         } else if (!strcasecmp(class->mode, "mp3nb")) {
1059                 ast_set_flag(class, MOH_SINGLE);
1060         } else if (!strcasecmp(class->mode, "quietmp3nb")) {
1061                 ast_set_flag(class, MOH_SINGLE | MOH_QUIET);
1062         } else if (!strcasecmp(class->mode, "quietmp3")) {
1063                 ast_set_flag(class, MOH_QUIET);
1064         }
1065                 
1066         class->srcfd = -1;
1067         class->pseudofd = -1;
1068
1069 #ifdef HAVE_DAHDI
1070         /* Open /dev/zap/pseudo for timing...  Is
1071            there a better, yet reliable way to do this? */
1072         class->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY);
1073         if (class->pseudofd < 0) {
1074                 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
1075         } else {
1076                 x = 320;
1077                 ioctl(class->pseudofd, DAHDI_SET_BLOCKSIZE, &x);
1078         }
1079 #endif
1080
1081         if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) {
1082                 ast_log(LOG_WARNING, "Unable to create moh thread...\n");
1083                 if (class->pseudofd > -1) {
1084                         close(class->pseudofd);
1085                         class->pseudofd = -1;
1086                 }
1087                 return -1;
1088         }
1089
1090         return 0;
1091 }
1092
1093 /*!
1094  * \note This function owns the reference it gets to moh
1095  */
1096 static int moh_register(struct mohclass *moh, int reload, int unref)
1097 {
1098         struct mohclass *mohclass = NULL;
1099
1100         if ((mohclass = get_mohbyname(moh->name, 0)) && !moh_diff(mohclass, moh)) {
1101                 if (!mohclass->delete) {
1102                         ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
1103                         mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1104                         if (unref) {
1105                                 moh = mohclass_unref(moh, "unreffing potential new moh class (it is a duplicate)");
1106                         }
1107                         return -1;
1108                 }
1109                 mohclass = mohclass_unref(mohclass, "Unreffing mohclass we just found by name");
1110         }
1111
1112         time(&moh->start);
1113         moh->start -= respawn_time;
1114         
1115         if (!strcasecmp(moh->mode, "files")) {
1116                 if (init_files_class(moh)) {
1117                         moh = mohclass_unref(moh, "unreffing potential new moh class (init_files_class failed)");
1118                         return -1;
1119                 }
1120         } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 
1121                         !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 
1122                         !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
1123                 if (init_app_class(moh)) {
1124                         moh = mohclass_unref(moh, "unreffing potential new moh class (init_app_class_failed)");
1125                         return -1;
1126                 }
1127         } else {
1128                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
1129                 moh = mohclass_unref(moh, "unreffing potential new moh class (unknown mode)");
1130                 return -1;
1131         }
1132
1133         ao2_t_link(mohclasses, moh, "Adding class to container");
1134
1135         if (unref) {
1136                 moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container");
1137         }
1138         
1139         return 0;
1140 }
1141
1142 static void local_ast_moh_cleanup(struct ast_channel *chan)
1143 {
1144         struct moh_files_state *state = chan->music_state;
1145
1146         if (state) {
1147                 ast_free(chan->music_state);
1148                 chan->music_state = NULL;
1149         }
1150 }
1151
1152 static void moh_class_destructor(void *obj);
1153
1154 static struct mohclass *moh_class_malloc(void)
1155 {
1156         struct mohclass *class;
1157
1158         if ((class = ao2_t_alloc(sizeof(*class), moh_class_destructor, "Allocating new moh class"))) {
1159                 class->format = AST_FORMAT_SLINEAR;
1160         }
1161
1162         return class;
1163 }
1164
1165 static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
1166 {
1167         struct mohclass *mohclass = NULL;
1168         struct moh_files_state *state = chan->music_state;
1169         int res;
1170
1171         /* The following is the order of preference for which class to use:
1172          * 1) The channels explicitly set musicclass, which should *only* be
1173          *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
1174          * 2) The mclass argument. If a channel is calling ast_moh_start() as the
1175          *    result of receiving a HOLD control frame, this should be the
1176          *    payload that came with the frame.
1177          * 3) The interpclass argument. This would be from the mohinterpret
1178          *    option from channel drivers. This is the same as the old musicclass
1179          *    option.
1180          * 4) The default class.
1181          */
1182         if (!ast_strlen_zero(chan->musicclass)) {
1183                 mohclass = get_mohbyname(chan->musicclass, 1);
1184         }
1185         if (!mohclass && !ast_strlen_zero(mclass)) {
1186                 mohclass = get_mohbyname(mclass, 1);
1187         }
1188         if (!mohclass && !ast_strlen_zero(interpclass)) {
1189                 mohclass = get_mohbyname(interpclass, 1);
1190         }
1191
1192         /* If no moh class found in memory, then check RT */
1193         if (!mohclass && ast_check_realtime("musiconhold")) {
1194                 struct ast_variable *var = NULL, *tmp = NULL;
1195
1196                 if (!ast_strlen_zero(chan->musicclass)) {
1197                         var = ast_load_realtime("musiconhold", "name", chan->musicclass, SENTINEL);
1198                 }
1199                 if (!var && !ast_strlen_zero(mclass))
1200                         var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL);
1201                 if (!var && !ast_strlen_zero(interpclass))
1202                         var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL);
1203                 if (!var)
1204                         var = ast_load_realtime("musiconhold", "name", "default", SENTINEL);
1205                 if (var && (mohclass = moh_class_malloc())) {
1206                         mohclass->realtime = 1;
1207                         for (tmp = var; tmp; tmp = tmp->next) {
1208                                 if (!strcasecmp(tmp->name, "name"))
1209                                         ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name));
1210                                 else if (!strcasecmp(tmp->name, "mode"))
1211                                         ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); 
1212                                 else if (!strcasecmp(tmp->name, "directory"))
1213                                         ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir));
1214                                 else if (!strcasecmp(tmp->name, "application"))
1215                                         ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args));
1216                                 else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value)))
1217                                         mohclass->digit = *tmp->value;
1218                                 else if (!strcasecmp(tmp->name, "random"))
1219                                         ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE);
1220                                 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random"))
1221                                         ast_set_flag(mohclass, MOH_RANDOMIZE);
1222                                 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 
1223                                         ast_set_flag(mohclass, MOH_SORTALPHA);
1224                                 else if (!strcasecmp(tmp->name, "format")) {
1225                                         mohclass->format = ast_getformatbyname(tmp->value);
1226                                         if (!mohclass->format) {
1227                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value);
1228                                                 mohclass->format = AST_FORMAT_SLINEAR;
1229                                         }
1230                                 }
1231                         }
1232                         ast_variables_destroy(var);
1233                         if (ast_strlen_zero(mohclass->dir)) {
1234                                 if (!strcasecmp(mohclass->mode, "custom")) {
1235                                         strcpy(mohclass->dir, "nodir");
1236                                 } else {
1237                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name);
1238                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)");
1239                                         return -1;
1240                                 }
1241                         }
1242                         if (ast_strlen_zero(mohclass->mode)) {
1243                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name);
1244                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)");
1245                                 return -1;
1246                         }
1247                         if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) {
1248                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name);
1249                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode");
1250                                 return -1;
1251                         }
1252
1253                         if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) {
1254                                 /* CACHERTCLASSES enabled, let's add this class to default tree */
1255                                 if (state && state->class) {
1256                                         /* Class already exist for this channel */
1257                                         ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1258                                         if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1259                                                 /* we found RT class with the same name, seems like we should continue playing existing one */
1260                                                 /* XXX This code is impossible to reach */
1261                                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has a class)");
1262                                                 mohclass = state->class;
1263                                         }
1264                                 }
1265                                 /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well.
1266                                  * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would
1267                                  * be that the destructor would be called when the generator on the channel is deactivated. The container then
1268                                  * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading
1269                                  * invalid memory.
1270                                  */
1271                                 moh_register(mohclass, 0, 0);
1272                         } else {
1273                                 /* We don't register RT moh class, so let's init it manualy */
1274
1275                                 time(&mohclass->start);
1276                                 mohclass->start -= respawn_time;
1277         
1278                                 if (!strcasecmp(mohclass->mode, "files")) {
1279                                         if (!moh_scan_files(mohclass)) {
1280                                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1281                                                 return -1;
1282                                         }
1283                                         if (strchr(mohclass->args, 'r'))
1284                                                 ast_set_flag(mohclass, MOH_RANDOMIZE);
1285                                 } else if (!strcasecmp(mohclass->mode, "mp3") || !strcasecmp(mohclass->mode, "mp3nb") || !strcasecmp(mohclass->mode, "quietmp3") || !strcasecmp(mohclass->mode, "quietmp3nb") || !strcasecmp(mohclass->mode, "httpmp3") || !strcasecmp(mohclass->mode, "custom")) {
1286
1287                                         if (!strcasecmp(mohclass->mode, "custom"))
1288                                                 ast_set_flag(mohclass, MOH_CUSTOM);
1289                                         else if (!strcasecmp(mohclass->mode, "mp3nb"))
1290                                                 ast_set_flag(mohclass, MOH_SINGLE);
1291                                         else if (!strcasecmp(mohclass->mode, "quietmp3nb"))
1292                                                 ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET);
1293                                         else if (!strcasecmp(mohclass->mode, "quietmp3"))
1294                                                 ast_set_flag(mohclass, MOH_QUIET);
1295                         
1296                                         mohclass->srcfd = -1;
1297 #ifdef HAVE_DAHDI
1298                                         /* Open /dev/dahdi/pseudo for timing...  Is
1299                                            there a better, yet reliable way to do this? */
1300                                         mohclass->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY);
1301                                         if (mohclass->pseudofd < 0) {
1302                                                 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
1303                                         } else {
1304                                                 int x = 320;
1305                                                 ioctl(mohclass->pseudofd, DAHDI_SET_BLOCKSIZE, &x);
1306                                         }
1307 #else
1308                                         mohclass->pseudofd = -1;
1309 #endif
1310                                         /* Let's check if this channel already had a moh class before */
1311                                         if (state && state->class) {
1312                                                 /* Class already exist for this channel */
1313                                                 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1314                                                 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1315                                                         /* we found RT class with the same name, seems like we should continue playing existing one */
1316                                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)");
1317                                                         mohclass = state->class;
1318                                                 }
1319                                         } else {
1320                                                 if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) {
1321                                                         ast_log(LOG_WARNING, "Unable to create moh...\n");
1322                                                         if (mohclass->pseudofd > -1) {
1323                                                                 close(mohclass->pseudofd);
1324                                                                 mohclass->pseudofd = -1;
1325                                                         }
1326                                                         mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)");
1327                                                         return -1;
1328                                                 }
1329                                         }
1330                                 } else {
1331                                         ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode);
1332                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)");
1333                                         return -1;
1334                                 }
1335                         }
1336                 } else if (var) {
1337                         ast_variables_destroy(var);
1338                 }
1339         }
1340
1341         if (!mohclass) {
1342                 mohclass = get_mohbyname("default", 1);
1343         }
1344
1345         if (!mohclass) {
1346                 return -1;
1347         }
1348
1349         manager_event(EVENT_FLAG_CALL, "MusicOnHold",
1350                 "State: Start\r\n"
1351                 "Channel: %s\r\n"
1352                 "UniqueID: %s\r\n",
1353                 chan->name, chan->uniqueid);
1354
1355         ast_set_flag(chan, AST_FLAG_MOH);
1356
1357         if (mohclass->total_files) {
1358                 res = ast_activate_generator(chan, &moh_file_stream, mohclass);
1359         } else {
1360                 res = ast_activate_generator(chan, &mohgen, mohclass);
1361         }
1362
1363         mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
1364
1365         return res;
1366 }
1367
1368 static void local_ast_moh_stop(struct ast_channel *chan)
1369 {
1370         struct moh_files_state *state = chan->music_state;
1371         ast_clear_flag(chan, AST_FLAG_MOH);
1372         ast_deactivate_generator(chan);
1373
1374         if (state) {
1375                 if (chan->stream) {
1376                         ast_closestream(chan->stream);
1377                         chan->stream = NULL;
1378                 }
1379         }
1380
1381         manager_event(EVENT_FLAG_CALL, "MusicOnHold",
1382                 "State: Stop\r\n"
1383                 "Channel: %s\r\n"
1384                 "UniqueID: %s\r\n",
1385                 chan->name, chan->uniqueid);
1386 }
1387
1388 static void moh_class_destructor(void *obj)
1389 {
1390         struct mohclass *class = obj;
1391         struct mohdata *member;
1392
1393         ast_debug(1, "Destroying MOH class '%s'\n", class->name);
1394
1395         if (class->pid > 1) {
1396                 char buff[8192];
1397                 int bytes, tbytes = 0, stime = 0, pid = 0;
1398
1399                 ast_log(LOG_DEBUG, "killing %d!\n", class->pid);
1400
1401                 stime = time(NULL) + 2;
1402                 pid = class->pid;
1403                 class->pid = 0;
1404
1405                 /* Back when this was just mpg123, SIGKILL was fine.  Now we need
1406                  * to give the process a reason and time enough to kill off its
1407                  * children. */
1408                 killpg(pid, SIGHUP);
1409                 usleep(100000);
1410                 killpg(pid, SIGTERM);
1411                 usleep(100000);
1412                 killpg(pid, SIGKILL);
1413
1414                 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 
1415                                 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) {
1416                         tbytes = tbytes + bytes;
1417                 }
1418
1419                 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1420
1421                 close(class->srcfd);
1422         }
1423
1424         while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) {
1425                 free(member);
1426         }
1427
1428         if (class->thread) {
1429                 pthread_cancel(class->thread);
1430                 pthread_join(class->thread, NULL);
1431                 class->thread = AST_PTHREADT_NULL;
1432         }
1433
1434         if (class->filearray) {
1435                 int i;
1436                 for (i = 0; i < class->total_files; i++) {
1437                         free(class->filearray[i]);
1438                 }
1439                 free(class->filearray);
1440                 class->filearray = NULL;
1441         }
1442 }
1443
1444 static int moh_class_mark(void *obj, void *arg, int flags)
1445 {
1446         struct mohclass *class = obj;
1447
1448         class->delete = 1;
1449
1450         return 0;
1451 }
1452
1453 static int moh_classes_delete_marked(void *obj, void *arg, int flags)
1454 {
1455         struct mohclass *class = obj;
1456
1457         return class->delete ? CMP_MATCH : 0;
1458 }
1459
1460 static int load_moh_classes(int reload)
1461 {
1462         struct ast_config *cfg;
1463         struct ast_variable *var;
1464         struct mohclass *class; 
1465         char *cat;
1466         int numclasses = 0;
1467         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1468
1469         cfg = ast_config_load("musiconhold.conf", config_flags);
1470
1471         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
1472                 return 0;
1473         }
1474
1475         if (reload) {
1476                 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1477         }
1478         
1479         ast_clear_flag(global_flags, AST_FLAGS_ALL);
1480
1481         cat = ast_category_browse(cfg, NULL);
1482         for (; cat; cat = ast_category_browse(cfg, cat)) {
1483                 /* Setup common options from [general] section */
1484                 if (!strcasecmp(cat, "general")) {
1485                         for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1486                                 if (!strcasecmp(var->name, "cachertclasses")) {
1487                                         ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES);
1488                                 } else {
1489                                         ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name);
1490                                 }
1491                         }
1492                 }
1493                 /* These names were deprecated in 1.4 and should not be used until after the next major release. */
1494                 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 
1495                                 !strcasecmp(cat, "general")) {
1496                         continue;
1497                 }
1498
1499                 if (!(class = moh_class_malloc())) {
1500                         break;
1501                 }
1502
1503                 ast_copy_string(class->name, cat, sizeof(class->name)); 
1504                 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1505                         if (!strcasecmp(var->name, "mode"))
1506                                 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
1507                         else if (!strcasecmp(var->name, "directory"))
1508                                 ast_copy_string(class->dir, var->value, sizeof(class->dir));
1509                         else if (!strcasecmp(var->name, "application"))
1510                                 ast_copy_string(class->args, var->value, sizeof(class->args));
1511                         else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value)))
1512                                 class->digit = *var->value;
1513                         else if (!strcasecmp(var->name, "random"))
1514                                 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1515                         else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random"))
1516                                 ast_set_flag(class, MOH_RANDOMIZE);
1517                         else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) 
1518                                 ast_set_flag(class, MOH_SORTALPHA);
1519                         else if (!strcasecmp(var->name, "format")) {
1520                                 class->format = ast_getformatbyname(var->value);
1521                                 if (!class->format) {
1522                                         ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1523                                         class->format = AST_FORMAT_SLINEAR;
1524                                 }
1525                         }
1526                 }
1527
1528                 if (ast_strlen_zero(class->dir)) {
1529                         if (!strcasecmp(class->mode, "custom")) {
1530                                 strcpy(class->dir, "nodir");
1531                         } else {
1532                                 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1533                                 class = mohclass_unref(class, "unreffing potential mohclass (no directory)");
1534                                 continue;
1535                         }
1536                 }
1537                 if (ast_strlen_zero(class->mode)) {
1538                         ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1539                         class = mohclass_unref(class, "unreffing potential mohclass (no mode)");
1540                         continue;
1541                 }
1542                 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1543                         ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1544                         class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)");
1545                         continue;
1546                 }
1547
1548                 /* Don't leak a class when it's already registered */
1549                 if (!moh_register(class, reload, 1)) {
1550                         numclasses++;
1551                 }
1552         }
1553
1554         ast_config_destroy(cfg);
1555
1556         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 
1557                         moh_classes_delete_marked, NULL, "Purge marked classes");
1558
1559         return numclasses;
1560 }
1561
1562 static void ast_moh_destroy(void)
1563 {
1564         ast_verb(2, "Destroying musiconhold processes\n");
1565         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback");
1566 }
1567
1568 static char *handle_cli_moh_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1569 {
1570         switch (cmd) {
1571         case CLI_INIT:
1572                 e->command = "moh reload";
1573                 e->usage =
1574                         "Usage: moh reload\n"
1575                         "       Reloads the MusicOnHold module.\n"
1576                         "       Alias for 'module reload res_musiconhold.so'\n";
1577                 return NULL;
1578         case CLI_GENERATE:
1579                 return NULL;
1580         }
1581
1582         if (a->argc != e->args)
1583                 return CLI_SHOWUSAGE;
1584
1585         reload();
1586
1587         return CLI_SUCCESS;
1588 }
1589
1590 static char *handle_cli_moh_show_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1591 {
1592         struct mohclass *class;
1593         struct ao2_iterator i;
1594
1595         switch (cmd) {
1596         case CLI_INIT:
1597                 e->command = "moh show files";
1598                 e->usage =
1599                         "Usage: moh show files\n"
1600                         "       Lists all loaded file-based MusicOnHold classes and their\n"
1601                         "       files.\n";
1602                 return NULL;
1603         case CLI_GENERATE:
1604                 return NULL;
1605         }
1606
1607         if (a->argc != e->args)
1608                 return CLI_SHOWUSAGE;
1609
1610         i = ao2_iterator_init(mohclasses, 0);
1611
1612         for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
1613                 int x;
1614
1615                 if (!class->total_files) {
1616                         continue;
1617                 }
1618
1619                 ast_cli(a->fd, "Class: %s\n", class->name);
1620                 for (x = 0; x < class->total_files; x++) {
1621                         ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
1622                 }
1623         }
1624
1625         return CLI_SUCCESS;
1626 }
1627
1628 static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1629 {
1630         struct mohclass *class;
1631         struct ao2_iterator i;
1632
1633         switch (cmd) {
1634         case CLI_INIT:
1635                 e->command = "moh show classes";
1636                 e->usage =
1637                         "Usage: moh show classes\n"
1638                         "       Lists all MusicOnHold classes.\n";
1639                 return NULL;
1640         case CLI_GENERATE:
1641                 return NULL;
1642         }
1643
1644         if (a->argc != e->args)
1645                 return CLI_SHOWUSAGE;
1646
1647         i = ao2_iterator_init(mohclasses, 0);
1648
1649         for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) {
1650                 ast_cli(a->fd, "Class: %s\n", class->name);
1651                 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1652                 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1653                 if (ast_test_flag(class, MOH_CUSTOM)) {
1654                         ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1655                 }
1656                 if (strcasecmp(class->mode, "files")) {
1657                         ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format));
1658                 }
1659         }
1660
1661         return CLI_SUCCESS;
1662 }
1663
1664 static struct ast_cli_entry cli_moh[] = {
1665         AST_CLI_DEFINE(handle_cli_moh_reload,       "Reload MusicOnHold"),
1666         AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"),
1667         AST_CLI_DEFINE(handle_cli_moh_show_files,   "List MusicOnHold file-based classes")
1668 };
1669
1670 static int moh_class_hash(const void *obj, const int flags)
1671 {
1672         const struct mohclass *class = obj;
1673
1674         return ast_str_case_hash(class->name);
1675 }
1676
1677 static int moh_class_cmp(void *obj, void *arg, int flags)
1678 {
1679         struct mohclass *class = obj, *class2 = arg;
1680
1681         return strcasecmp(class->name, class2->name) ? 0 : CMP_MATCH | CMP_STOP;
1682 }
1683
1684 static int load_module(void)
1685 {
1686         int res;
1687
1688         if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) {
1689                 return AST_MODULE_LOAD_DECLINE;
1690         }
1691
1692         if (!load_moh_classes(0)) {     /* No music classes configured, so skip it */
1693                 ast_log(LOG_WARNING, "No music on hold classes configured, "
1694                                 "disabling music on hold.\n");
1695         } else {
1696                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
1697                                 local_ast_moh_cleanup);
1698         }
1699
1700         res = ast_register_application_xml(play_moh, play_moh_exec);
1701         ast_register_atexit(ast_moh_destroy);
1702         ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh));
1703         if (!res)
1704                 res = ast_register_application_xml(wait_moh, wait_moh_exec);
1705         if (!res)
1706                 res = ast_register_application_xml(set_moh, set_moh_exec);
1707         if (!res)
1708                 res = ast_register_application_xml(start_moh, start_moh_exec);
1709         if (!res)
1710                 res = ast_register_application_xml(stop_moh, stop_moh_exec);
1711
1712         return AST_MODULE_LOAD_SUCCESS;
1713 }
1714
1715 static int reload(void)
1716 {
1717         if (load_moh_classes(1)) {
1718                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
1719                                 local_ast_moh_cleanup);
1720         }
1721
1722         return AST_MODULE_LOAD_SUCCESS;
1723 }
1724
1725 static int moh_class_inuse(void *obj, void *arg, int flags)
1726 {
1727         struct mohclass *class = obj;
1728
1729         return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP;
1730 }
1731
1732 static int unload_module(void)
1733 {
1734         int res = 0;
1735         struct mohclass *class = NULL;
1736
1737         /* XXX This check shouldn't be required if module ref counting was being used
1738          * properly ... */
1739         if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) {
1740                 class = mohclass_unref(class, "unref of class from module unload callback");
1741                 res = -1;
1742         }
1743
1744         if (res < 0) {
1745                 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n");
1746                 return res;
1747         }
1748
1749         ast_uninstall_music_functions();
1750
1751         ast_moh_destroy();
1752         res = ast_unregister_application(play_moh);
1753         res |= ast_unregister_application(wait_moh);
1754         res |= ast_unregister_application(set_moh);
1755         res |= ast_unregister_application(start_moh);
1756         res |= ast_unregister_application(stop_moh);
1757         ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh));
1758         ast_unregister_atexit(ast_moh_destroy);
1759
1760         return res;
1761 }
1762
1763 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Music On Hold Resource",
1764         .load = load_module,
1765         .unload = unload_module,
1766         .reload = reload,
1767 );