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