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