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