Move music on hold related applications documentation to XML.
[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                 class->thread = AST_PTHREADT_NULL;
1431         }
1432
1433         if (class->filearray) {
1434                 int i;
1435                 for (i = 0; i < class->total_files; i++) {
1436                         free(class->filearray[i]);
1437                 }
1438                 free(class->filearray);
1439                 class->filearray = NULL;
1440         }
1441 }
1442
1443 static int moh_class_mark(void *obj, void *arg, int flags)
1444 {
1445         struct mohclass *class = obj;
1446
1447         class->delete = 1;
1448
1449         return 0;
1450 }
1451
1452 static int moh_classes_delete_marked(void *obj, void *arg, int flags)
1453 {
1454         struct mohclass *class = obj;
1455
1456         return class->delete ? CMP_MATCH : 0;
1457 }
1458
1459 static int load_moh_classes(int reload)
1460 {
1461         struct ast_config *cfg;
1462         struct ast_variable *var;
1463         struct mohclass *class; 
1464         char *cat;
1465         int numclasses = 0;
1466         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1467
1468         cfg = ast_config_load("musiconhold.conf", config_flags);
1469
1470         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
1471                 return 0;
1472         }
1473
1474         if (reload) {
1475                 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1476         }
1477         
1478         ast_clear_flag(global_flags, AST_FLAGS_ALL);
1479
1480         cat = ast_category_browse(cfg, NULL);
1481         for (; cat; cat = ast_category_browse(cfg, cat)) {
1482                 /* Setup common options from [general] section */
1483                 if (!strcasecmp(cat, "general")) {
1484                         for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1485                                 if (!strcasecmp(var->name, "cachertclasses")) {
1486                                         ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES);
1487                                 } else {
1488                                         ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name);
1489                                 }
1490                         }
1491                 }
1492                 /* These names were deprecated in 1.4 and should not be used until after the next major release. */
1493                 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 
1494                                 !strcasecmp(cat, "general")) {
1495                         continue;
1496                 }
1497
1498                 if (!(class = moh_class_malloc())) {
1499                         break;
1500                 }
1501
1502                 ast_copy_string(class->name, cat, sizeof(class->name)); 
1503                 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1504                         if (!strcasecmp(var->name, "mode"))
1505                                 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
1506                         else if (!strcasecmp(var->name, "directory"))
1507                                 ast_copy_string(class->dir, var->value, sizeof(class->dir));
1508                         else if (!strcasecmp(var->name, "application"))
1509                                 ast_copy_string(class->args, var->value, sizeof(class->args));
1510                         else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value)))
1511                                 class->digit = *var->value;
1512                         else if (!strcasecmp(var->name, "random"))
1513                                 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1514                         else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random"))
1515                                 ast_set_flag(class, MOH_RANDOMIZE);
1516                         else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) 
1517                                 ast_set_flag(class, MOH_SORTALPHA);
1518                         else if (!strcasecmp(var->name, "format")) {
1519                                 class->format = ast_getformatbyname(var->value);
1520                                 if (!class->format) {
1521                                         ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1522                                         class->format = AST_FORMAT_SLINEAR;
1523                                 }
1524                         }
1525                 }
1526
1527                 if (ast_strlen_zero(class->dir)) {
1528                         if (!strcasecmp(class->mode, "custom")) {
1529                                 strcpy(class->dir, "nodir");
1530                         } else {
1531                                 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1532                                 class = mohclass_unref(class, "unreffing potential mohclass (no directory)");
1533                                 continue;
1534                         }
1535                 }
1536                 if (ast_strlen_zero(class->mode)) {
1537                         ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1538                         class = mohclass_unref(class, "unreffing potential mohclass (no mode)");
1539                         continue;
1540                 }
1541                 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1542                         ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1543                         class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)");
1544                         continue;
1545                 }
1546
1547                 /* Don't leak a class when it's already registered */
1548                 if (!moh_register(class, reload, 1)) {
1549                         numclasses++;
1550                 }
1551         }
1552
1553         ast_config_destroy(cfg);
1554
1555         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 
1556                         moh_classes_delete_marked, NULL, "Purge marked classes");
1557
1558         return numclasses;
1559 }
1560
1561 static void ast_moh_destroy(void)
1562 {
1563         ast_verb(2, "Destroying musiconhold processes\n");
1564         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback");
1565 }
1566
1567 static char *handle_cli_moh_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1568 {
1569         switch (cmd) {
1570         case CLI_INIT:
1571                 e->command = "moh reload";
1572                 e->usage =
1573                         "Usage: moh reload\n"
1574                         "       Reloads the MusicOnHold module.\n"
1575                         "       Alias for 'module reload res_musiconhold.so'\n";
1576                 return NULL;
1577         case CLI_GENERATE:
1578                 return NULL;
1579         }
1580
1581         if (a->argc != e->args)
1582                 return CLI_SHOWUSAGE;
1583
1584         reload();
1585
1586         return CLI_SUCCESS;
1587 }
1588
1589 static char *handle_cli_moh_show_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1590 {
1591         struct mohclass *class;
1592         struct ao2_iterator i;
1593
1594         switch (cmd) {
1595         case CLI_INIT:
1596                 e->command = "moh show files";
1597                 e->usage =
1598                         "Usage: moh show files\n"
1599                         "       Lists all loaded file-based MusicOnHold classes and their\n"
1600                         "       files.\n";
1601                 return NULL;
1602         case CLI_GENERATE:
1603                 return NULL;
1604         }
1605
1606         if (a->argc != e->args)
1607                 return CLI_SHOWUSAGE;
1608
1609         i = ao2_iterator_init(mohclasses, 0);
1610
1611         for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
1612                 int x;
1613
1614                 if (!class->total_files) {
1615                         continue;
1616                 }
1617
1618                 ast_cli(a->fd, "Class: %s\n", class->name);
1619                 for (x = 0; x < class->total_files; x++) {
1620                         ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
1621                 }
1622         }
1623
1624         return CLI_SUCCESS;
1625 }
1626
1627 static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1628 {
1629         struct mohclass *class;
1630         struct ao2_iterator i;
1631
1632         switch (cmd) {
1633         case CLI_INIT:
1634                 e->command = "moh show classes";
1635                 e->usage =
1636                         "Usage: moh show classes\n"
1637                         "       Lists all MusicOnHold classes.\n";
1638                 return NULL;
1639         case CLI_GENERATE:
1640                 return NULL;
1641         }
1642
1643         if (a->argc != e->args)
1644                 return CLI_SHOWUSAGE;
1645
1646         i = ao2_iterator_init(mohclasses, 0);
1647
1648         for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) {
1649                 ast_cli(a->fd, "Class: %s\n", class->name);
1650                 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1651                 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1652                 if (ast_test_flag(class, MOH_CUSTOM)) {
1653                         ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1654                 }
1655                 if (strcasecmp(class->mode, "files")) {
1656                         ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format));
1657                 }
1658         }
1659
1660         return CLI_SUCCESS;
1661 }
1662
1663 static struct ast_cli_entry cli_moh[] = {
1664         AST_CLI_DEFINE(handle_cli_moh_reload,       "Reload MusicOnHold"),
1665         AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"),
1666         AST_CLI_DEFINE(handle_cli_moh_show_files,   "List MusicOnHold file-based classes")
1667 };
1668
1669 static int moh_class_hash(const void *obj, const int flags)
1670 {
1671         const struct mohclass *class = obj;
1672
1673         return ast_str_case_hash(class->name);
1674 }
1675
1676 static int moh_class_cmp(void *obj, void *arg, int flags)
1677 {
1678         struct mohclass *class = obj, *class2 = arg;
1679
1680         return strcasecmp(class->name, class2->name) ? 0 : CMP_MATCH | CMP_STOP;
1681 }
1682
1683 static int load_module(void)
1684 {
1685         int res;
1686
1687         if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) {
1688                 return AST_MODULE_LOAD_DECLINE;
1689         }
1690
1691         if (!load_moh_classes(0)) {     /* No music classes configured, so skip it */
1692                 ast_log(LOG_WARNING, "No music on hold classes configured, "
1693                                 "disabling music on hold.\n");
1694         } else {
1695                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
1696                                 local_ast_moh_cleanup);
1697         }
1698
1699         res = ast_register_application_xml(play_moh, play_moh_exec);
1700         ast_register_atexit(ast_moh_destroy);
1701         ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh));
1702         if (!res)
1703                 res = ast_register_application_xml(wait_moh, wait_moh_exec);
1704         if (!res)
1705                 res = ast_register_application_xml(set_moh, set_moh_exec);
1706         if (!res)
1707                 res = ast_register_application_xml(start_moh, start_moh_exec);
1708         if (!res)
1709                 res = ast_register_application_xml(stop_moh, stop_moh_exec);
1710
1711         return AST_MODULE_LOAD_SUCCESS;
1712 }
1713
1714 static int reload(void)
1715 {
1716         if (load_moh_classes(1)) {
1717                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
1718                                 local_ast_moh_cleanup);
1719         }
1720
1721         return AST_MODULE_LOAD_SUCCESS;
1722 }
1723
1724 static int moh_class_inuse(void *obj, void *arg, int flags)
1725 {
1726         struct mohclass *class = obj;
1727
1728         return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP;
1729 }
1730
1731 static int unload_module(void)
1732 {
1733         int res = 0;
1734         struct mohclass *class = NULL;
1735
1736         /* XXX This check shouldn't be required if module ref counting was being used
1737          * properly ... */
1738         if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) {
1739                 class = mohclass_unref(class, "unref of class from module unload callback");
1740                 res = -1;
1741         }
1742
1743         if (res < 0) {
1744                 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n");
1745                 return res;
1746         }
1747
1748         ast_uninstall_music_functions();
1749
1750         ast_moh_destroy();
1751         res = ast_unregister_application(play_moh);
1752         res |= ast_unregister_application(wait_moh);
1753         res |= ast_unregister_application(set_moh);
1754         res |= ast_unregister_application(start_moh);
1755         res |= ast_unregister_application(stop_moh);
1756         ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh));
1757         ast_unregister_atexit(ast_moh_destroy);
1758
1759         return res;
1760 }
1761
1762 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Music On Hold Resource",
1763         .load = load_module,
1764         .unload = unload_module,
1765         .reload = reload,
1766 );