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