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