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