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