Media Project Phase2: SILK 8khz-24khz, SLINEAR 8khz-192khz, SPEEX 32khz, hd audio...
[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         struct ast_format 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         struct ast_format 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         struct ast_format 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.id && 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_debug(1, "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         ast_format_copy(&moh->f.subclass.format, &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         struct ast_format 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         ast_format_copy(&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.id && 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                 ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
1280                 class->srcfd = -1;
1281         }
1282
1283         return class;
1284 }
1285
1286 static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
1287 {
1288         struct mohclass *mohclass = NULL;
1289         struct moh_files_state *state = chan->music_state;
1290         struct ast_variable *var = NULL;
1291         int res;
1292         int realtime_possible = ast_check_realtime("musiconhold");
1293
1294         /* The following is the order of preference for which class to use:
1295          * 1) The channels explicitly set musicclass, which should *only* be
1296          *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
1297          * 2) The mclass argument. If a channel is calling ast_moh_start() as the
1298          *    result of receiving a HOLD control frame, this should be the
1299          *    payload that came with the frame.
1300          * 3) The interpclass argument. This would be from the mohinterpret
1301          *    option from channel drivers. This is the same as the old musicclass
1302          *    option.
1303          * 4) The default class.
1304          */
1305         if (!ast_strlen_zero(chan->musicclass)) {
1306                 mohclass = get_mohbyname(chan->musicclass, 1, 0);
1307                 if (!mohclass && realtime_possible) {
1308                         var = ast_load_realtime("musiconhold", "name", chan->musicclass, SENTINEL);
1309                 }
1310         }
1311         if (!mohclass && !var && !ast_strlen_zero(mclass)) {
1312                 mohclass = get_mohbyname(mclass, 1, 0);
1313                 if (!mohclass && realtime_possible) {
1314                         var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL);
1315                 }
1316         }
1317         if (!mohclass && !var && !ast_strlen_zero(interpclass)) {
1318                 mohclass = get_mohbyname(interpclass, 1, 0);
1319                 if (!mohclass && realtime_possible) {
1320                         var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL);
1321                 }
1322         }
1323
1324         if (!mohclass && !var) {
1325                 mohclass = get_mohbyname("default", 1, 0);
1326                 if (!mohclass && realtime_possible) {
1327                         var = ast_load_realtime("musiconhold", "name", "default", SENTINEL);
1328                 }
1329         }
1330
1331         /* If no moh class found in memory, then check RT. Note that the logic used
1332          * above guarantees that if var is non-NULL, then mohclass must be NULL.
1333          */
1334         if (var) {
1335                 struct ast_variable *tmp = NULL;
1336
1337                 if ((mohclass = moh_class_malloc())) {
1338                         mohclass->realtime = 1;
1339                         for (tmp = var; tmp; tmp = tmp->next) {
1340                                 if (!strcasecmp(tmp->name, "name"))
1341                                         ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name));
1342                                 else if (!strcasecmp(tmp->name, "mode"))
1343                                         ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); 
1344                                 else if (!strcasecmp(tmp->name, "directory"))
1345                                         ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir));
1346                                 else if (!strcasecmp(tmp->name, "application"))
1347                                         ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args));
1348                                 else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value)))
1349                                         mohclass->digit = *tmp->value;
1350                                 else if (!strcasecmp(tmp->name, "random"))
1351                                         ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE);
1352                                 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random"))
1353                                         ast_set_flag(mohclass, MOH_RANDOMIZE);
1354                                 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 
1355                                         ast_set_flag(mohclass, MOH_SORTALPHA);
1356                                 else if (!strcasecmp(tmp->name, "format")) {
1357                                         ast_getformatbyname(tmp->value, &mohclass->format);
1358                                         if (!mohclass->format.id) {
1359                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value);
1360                                                 ast_format_set(&mohclass->format, AST_FORMAT_SLINEAR, 0);
1361                                         }
1362                                 }
1363                         }
1364                         ast_variables_destroy(var);
1365                         if (ast_strlen_zero(mohclass->dir)) {
1366                                 if (!strcasecmp(mohclass->mode, "custom")) {
1367                                         strcpy(mohclass->dir, "nodir");
1368                                 } else {
1369                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name);
1370                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)");
1371                                         return -1;
1372                                 }
1373                         }
1374                         if (ast_strlen_zero(mohclass->mode)) {
1375                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name);
1376                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)");
1377                                 return -1;
1378                         }
1379                         if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) {
1380                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name);
1381                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode");
1382                                 return -1;
1383                         }
1384
1385                         if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) {
1386                                 /* CACHERTCLASSES enabled, let's add this class to default tree */
1387                                 if (state && state->class) {
1388                                         /* Class already exist for this channel */
1389                                         ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1390                                         if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1391                                                 /* we found RT class with the same name, seems like we should continue playing existing one */
1392                                                 /* XXX This code is impossible to reach */
1393                                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has a class)");
1394                                                 mohclass = state->class;
1395                                         }
1396                                 }
1397                                 /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well.
1398                                  * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would
1399                                  * be that the destructor would be called when the generator on the channel is deactivated. The container then
1400                                  * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading
1401                                  * invalid memory.
1402                                  */
1403                                 if (moh_register(mohclass, 0, DONT_UNREF) == -1) {
1404                                         mohclass = mohclass_unref(mohclass, "unreffing mohclass failed to register");
1405                                         return -1;
1406                                 }
1407                         } else {
1408                                 /* We don't register RT moh class, so let's init it manualy */
1409
1410                                 time(&mohclass->start);
1411                                 mohclass->start -= respawn_time;
1412
1413                                 if (!strcasecmp(mohclass->mode, "files")) {
1414                                         if (!moh_scan_files(mohclass)) {
1415                                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1416                                                 return -1;
1417                                         }
1418                                         if (strchr(mohclass->args, 'r'))
1419                                                 ast_set_flag(mohclass, MOH_RANDOMIZE);
1420                                 } 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")) {
1421
1422                                         if (!strcasecmp(mohclass->mode, "custom"))
1423                                                 ast_set_flag(mohclass, MOH_CUSTOM);
1424                                         else if (!strcasecmp(mohclass->mode, "mp3nb"))
1425                                                 ast_set_flag(mohclass, MOH_SINGLE);
1426                                         else if (!strcasecmp(mohclass->mode, "quietmp3nb"))
1427                                                 ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET);
1428                                         else if (!strcasecmp(mohclass->mode, "quietmp3"))
1429                                                 ast_set_flag(mohclass, MOH_QUIET);
1430
1431                                         mohclass->srcfd = -1;
1432                                         if (!(mohclass->timer = ast_timer_open())) {
1433                                                 ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1434                                         }
1435                                         if (mohclass->timer && ast_timer_set_rate(mohclass->timer, 25)) {
1436                                                 ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1437                                                 ast_timer_close(mohclass->timer);
1438                                                 mohclass->timer = NULL;
1439                                         }
1440
1441                                         /* Let's check if this channel already had a moh class before */
1442                                         if (state && state->class) {
1443                                                 /* Class already exist for this channel */
1444                                                 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1445                                                 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1446                                                         /* we found RT class with the same name, seems like we should continue playing existing one */
1447                                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)");
1448                                                         mohclass = state->class;
1449                                                 }
1450                                         } else {
1451                                                 if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) {
1452                                                         ast_log(LOG_WARNING, "Unable to create moh...\n");
1453                                                         if (mohclass->timer) {
1454                                                                 ast_timer_close(mohclass->timer);
1455                                                                 mohclass->timer = NULL;
1456                                                         }
1457                                                         mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)");
1458                                                         return -1;
1459                                                 }
1460                                         }
1461                                 } else {
1462                                         ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode);
1463                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)");
1464                                         return -1;
1465                                 }
1466                         }
1467                 } else {
1468                         ast_variables_destroy(var);
1469                 }
1470         }
1471
1472         if (!mohclass) {
1473                 return -1;
1474         }
1475
1476         ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold",
1477                 "State: Start\r\n"
1478                 "Channel: %s\r\n"
1479                 "UniqueID: %s\r\n"
1480                 "Class: %s\r\n",
1481                 chan->name, chan->uniqueid,
1482                 mohclass->name);
1483
1484         ast_set_flag(chan, AST_FLAG_MOH);
1485
1486         if (mohclass->total_files) {
1487                 res = ast_activate_generator(chan, &moh_file_stream, mohclass);
1488         } else {
1489                 res = ast_activate_generator(chan, &mohgen, mohclass);
1490         }
1491
1492         mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
1493
1494         return res;
1495 }
1496
1497 static void local_ast_moh_stop(struct ast_channel *chan)
1498 {
1499         ast_clear_flag(chan, AST_FLAG_MOH);
1500         ast_deactivate_generator(chan);
1501
1502         ast_channel_lock(chan);
1503         if (chan->music_state) {
1504                 if (chan->stream) {
1505                         ast_closestream(chan->stream);
1506                         chan->stream = NULL;
1507                 }
1508         }
1509
1510         ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold",
1511                 "State: Stop\r\n"
1512                 "Channel: %s\r\n"
1513                 "UniqueID: %s\r\n",
1514                 chan->name, chan->uniqueid);
1515         ast_channel_unlock(chan);
1516 }
1517
1518 static void moh_class_destructor(void *obj)
1519 {
1520         struct mohclass *class = obj;
1521         struct mohdata *member;
1522         pthread_t tid = 0;
1523
1524         ast_debug(1, "Destroying MOH class '%s'\n", class->name);
1525
1526         /* Kill the thread first, so it cannot restart the child process while the
1527          * class is being destroyed */
1528         if (class->thread != AST_PTHREADT_NULL && class->thread != 0) {
1529                 tid = class->thread;
1530                 class->thread = AST_PTHREADT_NULL;
1531                 pthread_cancel(tid);
1532                 /* We'll collect the exit status later, after we ensure all the readers
1533                  * are dead. */
1534         }
1535
1536         if (class->pid > 1) {
1537                 char buff[8192];
1538                 int bytes, tbytes = 0, stime = 0, pid = 0;
1539
1540                 ast_debug(1, "killing %d!\n", class->pid);
1541
1542                 stime = time(NULL) + 2;
1543                 pid = class->pid;
1544                 class->pid = 0;
1545
1546                 /* Back when this was just mpg123, SIGKILL was fine.  Now we need
1547                  * to give the process a reason and time enough to kill off its
1548                  * children. */
1549                 do {
1550                         if (killpg(pid, SIGHUP) < 0) {
1551                                 ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
1552                         }
1553                         usleep(100000);
1554                         if (killpg(pid, SIGTERM) < 0) {
1555                                 if (errno == ESRCH) {
1556                                         break;
1557                                 }
1558                                 ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
1559                         }
1560                         usleep(100000);
1561                         if (killpg(pid, SIGKILL) < 0) {
1562                                 if (errno == ESRCH) {
1563                                         break;
1564                                 }
1565                                 ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
1566                         }
1567                 } while (0);
1568
1569                 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 
1570                                 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) {
1571                         tbytes = tbytes + bytes;
1572                 }
1573
1574                 ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1575
1576                 close(class->srcfd);
1577         }
1578
1579         while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) {
1580                 free(member);
1581         }
1582
1583         if (class->filearray) {
1584                 int i;
1585                 for (i = 0; i < class->total_files; i++) {
1586                         free(class->filearray[i]);
1587                 }
1588                 free(class->filearray);
1589                 class->filearray = NULL;
1590         }
1591
1592         if (class->timer) {
1593                 ast_timer_close(class->timer);
1594                 class->timer = NULL;
1595         }
1596
1597         /* Finally, collect the exit status of the monitor thread */
1598         if (tid > 0) {
1599                 pthread_join(tid, NULL);
1600         }
1601 }
1602
1603 static int moh_class_mark(void *obj, void *arg, int flags)
1604 {
1605         struct mohclass *class = obj;
1606
1607         class->delete = 1;
1608
1609         return 0;
1610 }
1611
1612 static int moh_classes_delete_marked(void *obj, void *arg, int flags)
1613 {
1614         struct mohclass *class = obj;
1615
1616         return class->delete ? CMP_MATCH : 0;
1617 }
1618
1619 static int load_moh_classes(int reload)
1620 {
1621         struct ast_config *cfg;
1622         struct ast_variable *var;
1623         struct mohclass *class; 
1624         char *cat;
1625         int numclasses = 0;
1626         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1627
1628         cfg = ast_config_load("musiconhold.conf", config_flags);
1629
1630         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
1631                 if (ast_check_realtime("musiconhold") && reload) {
1632                         ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1633                         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes");
1634                 }
1635                 if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1636                         moh_rescan_files();
1637                 }
1638                 return 0;
1639         }
1640
1641         if (reload) {
1642                 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1643         }
1644
1645         ast_clear_flag(global_flags, AST_FLAGS_ALL);
1646
1647         cat = ast_category_browse(cfg, NULL);
1648         for (; cat; cat = ast_category_browse(cfg, cat)) {
1649                 /* Setup common options from [general] section */
1650                 if (!strcasecmp(cat, "general")) {
1651                         for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1652                                 if (!strcasecmp(var->name, "cachertclasses")) {
1653                                         ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES);
1654                                 } else {
1655                                         ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name);
1656                                 }
1657                         }
1658                 }
1659                 /* These names were deprecated in 1.4 and should not be used until after the next major release. */
1660                 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 
1661                                 !strcasecmp(cat, "general")) {
1662                         continue;
1663                 }
1664
1665                 if (!(class = moh_class_malloc())) {
1666                         break;
1667                 }
1668
1669                 ast_copy_string(class->name, cat, sizeof(class->name)); 
1670                 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1671                         if (!strcasecmp(var->name, "mode"))
1672                                 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
1673                         else if (!strcasecmp(var->name, "directory"))
1674                                 ast_copy_string(class->dir, var->value, sizeof(class->dir));
1675                         else if (!strcasecmp(var->name, "application"))
1676                                 ast_copy_string(class->args, var->value, sizeof(class->args));
1677                         else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value)))
1678                                 class->digit = *var->value;
1679                         else if (!strcasecmp(var->name, "random"))
1680                                 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1681                         else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random"))
1682                                 ast_set_flag(class, MOH_RANDOMIZE);
1683                         else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) 
1684                                 ast_set_flag(class, MOH_SORTALPHA);
1685                         else if (!strcasecmp(var->name, "format")) {
1686                                 ast_getformatbyname(var->value, &class->format);
1687                                 if (!class->format.id) {
1688                                         ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1689                                         ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
1690                                 }
1691                         }
1692                 }
1693
1694                 if (ast_strlen_zero(class->dir)) {
1695                         if (!strcasecmp(class->mode, "custom")) {
1696                                 strcpy(class->dir, "nodir");
1697                         } else {
1698                                 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1699                                 class = mohclass_unref(class, "unreffing potential mohclass (no directory)");
1700                                 continue;
1701                         }
1702                 }
1703                 if (ast_strlen_zero(class->mode)) {
1704                         ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1705                         class = mohclass_unref(class, "unreffing potential mohclass (no mode)");
1706                         continue;
1707                 }
1708                 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1709                         ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1710                         class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)");
1711                         continue;
1712                 }
1713
1714                 /* Don't leak a class when it's already registered */
1715                 if (!moh_register(class, reload, HANDLE_REF)) {
1716                         numclasses++;
1717                 }
1718         }
1719
1720         ast_config_destroy(cfg);
1721
1722         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 
1723                         moh_classes_delete_marked, NULL, "Purge marked classes");
1724
1725         return numclasses;
1726 }
1727
1728 static void ast_moh_destroy(void)
1729 {
1730         ast_verb(2, "Destroying musiconhold processes\n");
1731         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback");
1732 }
1733
1734 static char *handle_cli_moh_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1735 {
1736         switch (cmd) {
1737         case CLI_INIT:
1738                 e->command = "moh reload";
1739                 e->usage =
1740                         "Usage: moh reload\n"
1741                         "       Reloads the MusicOnHold module.\n"
1742                         "       Alias for 'module reload res_musiconhold.so'\n";
1743                 return NULL;
1744         case CLI_GENERATE:
1745                 return NULL;
1746         }
1747
1748         if (a->argc != e->args)
1749                 return CLI_SHOWUSAGE;
1750
1751         reload();
1752
1753         return CLI_SUCCESS;
1754 }
1755
1756 static char *handle_cli_moh_show_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1757 {
1758         struct mohclass *class;
1759         struct ao2_iterator i;
1760
1761         switch (cmd) {
1762         case CLI_INIT:
1763                 e->command = "moh show files";
1764                 e->usage =
1765                         "Usage: moh show files\n"
1766                         "       Lists all loaded file-based MusicOnHold classes and their\n"
1767                         "       files.\n";
1768                 return NULL;
1769         case CLI_GENERATE:
1770                 return NULL;
1771         }
1772
1773         if (a->argc != e->args)
1774                 return CLI_SHOWUSAGE;
1775
1776         i = ao2_iterator_init(mohclasses, 0);
1777         for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
1778                 int x;
1779
1780                 if (!class->total_files) {
1781                         continue;
1782                 }
1783
1784                 ast_cli(a->fd, "Class: %s\n", class->name);
1785                 for (x = 0; x < class->total_files; x++) {
1786                         ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
1787                 }
1788         }
1789         ao2_iterator_destroy(&i);
1790
1791         return CLI_SUCCESS;
1792 }
1793
1794 static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1795 {
1796         struct mohclass *class;
1797         struct ao2_iterator i;
1798
1799         switch (cmd) {
1800         case CLI_INIT:
1801                 e->command = "moh show classes";
1802                 e->usage =
1803                         "Usage: moh show classes\n"
1804                         "       Lists all MusicOnHold classes.\n";
1805                 return NULL;
1806         case CLI_GENERATE:
1807                 return NULL;
1808         }
1809
1810         if (a->argc != e->args)
1811                 return CLI_SHOWUSAGE;
1812
1813         i = ao2_iterator_init(mohclasses, 0);
1814         for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) {
1815                 ast_cli(a->fd, "Class: %s\n", class->name);
1816                 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1817                 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1818                 if (ast_test_flag(class, MOH_CUSTOM)) {
1819                         ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1820                 }
1821                 if (strcasecmp(class->mode, "files")) {
1822                         ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(&class->format));
1823                 }
1824         }
1825         ao2_iterator_destroy(&i);
1826
1827         return CLI_SUCCESS;
1828 }
1829
1830 static struct ast_cli_entry cli_moh[] = {
1831         AST_CLI_DEFINE(handle_cli_moh_reload,       "Reload MusicOnHold"),
1832         AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"),
1833         AST_CLI_DEFINE(handle_cli_moh_show_files,   "List MusicOnHold file-based classes")
1834 };
1835
1836 static int moh_class_hash(const void *obj, const int flags)
1837 {
1838         const struct mohclass *class = obj;
1839
1840         return ast_str_case_hash(class->name);
1841 }
1842
1843 static int moh_class_cmp(void *obj, void *arg, int flags)
1844 {
1845         struct mohclass *class = obj, *class2 = arg;
1846
1847         return strcasecmp(class->name, class2->name) ? 0 :
1848                 (flags & MOH_NOTDELETED) && (class->delete || class2->delete) ? 0 :
1849                 CMP_MATCH | CMP_STOP;
1850 }
1851
1852 static int load_module(void)
1853 {
1854         int res;
1855
1856         if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) {
1857                 return AST_MODULE_LOAD_DECLINE;
1858         }
1859
1860         if (!load_moh_classes(0) && ast_check_realtime("musiconhold") == 0) {   /* No music classes configured, so skip it */
1861                 ast_log(LOG_WARNING, "No music on hold classes configured, "
1862                                 "disabling music on hold.\n");
1863         } else {
1864                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
1865                                 local_ast_moh_cleanup);
1866         }
1867
1868         res = ast_register_application_xml(play_moh, play_moh_exec);
1869         ast_register_atexit(ast_moh_destroy);
1870         ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh));
1871         if (!res)
1872                 res = ast_register_application_xml(wait_moh, wait_moh_exec);
1873         if (!res)
1874                 res = ast_register_application_xml(set_moh, set_moh_exec);
1875         if (!res)
1876                 res = ast_register_application_xml(start_moh, start_moh_exec);
1877         if (!res)
1878                 res = ast_register_application_xml(stop_moh, stop_moh_exec);
1879
1880         return AST_MODULE_LOAD_SUCCESS;
1881 }
1882
1883 static int reload(void)
1884 {
1885         if (load_moh_classes(1)) {
1886                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
1887                                 local_ast_moh_cleanup);
1888         }
1889
1890         return AST_MODULE_LOAD_SUCCESS;
1891 }
1892
1893 static int moh_class_inuse(void *obj, void *arg, int flags)
1894 {
1895         struct mohclass *class = obj;
1896
1897         return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP;
1898 }
1899
1900 static int unload_module(void)
1901 {
1902         int res = 0;
1903         struct mohclass *class = NULL;
1904
1905         /* XXX This check shouldn't be required if module ref counting was being used
1906          * properly ... */
1907         if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) {
1908                 class = mohclass_unref(class, "unref of class from module unload callback");
1909                 res = -1;
1910         }
1911
1912         if (res < 0) {
1913                 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n");
1914                 return res;
1915         }
1916
1917         ast_uninstall_music_functions();
1918
1919         ast_moh_destroy();
1920         res = ast_unregister_application(play_moh);
1921         res |= ast_unregister_application(wait_moh);
1922         res |= ast_unregister_application(set_moh);
1923         res |= ast_unregister_application(start_moh);
1924         res |= ast_unregister_application(stop_moh);
1925         ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh));
1926         ast_unregister_atexit(ast_moh_destroy);
1927
1928         return res;
1929 }
1930
1931 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Music On Hold Resource",
1932         .load = load_module,
1933         .unload = unload_module,
1934         .reload = reload,
1935         .load_pri = AST_MODPRI_CHANNEL_DEPEND,
1936 );