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