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