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