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