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