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