Tue Mar 18 07:00:01 CET 2003
[asterisk/asterisk.git] / res / res_musiconhold.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Routines implementing call parking
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/options.h>
20 #include <asterisk/module.h>
21 #include <asterisk/translate.h>
22 #include <asterisk/say.h>
23 #include <asterisk/channel_pvt.h>
24 #include <asterisk/musiconhold.h>
25 #include <asterisk/config.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <sys/time.h>
33 #include <sys/signal.h>
34 #include <netinet/in.h>
35 #include <sys/stat.h>
36 #include <dirent.h>
37 #ifdef ZAPATA_MOH
38 #include <linux/zaptel.h>
39 #endif
40 #include <unistd.h>
41 #include <sys/ioctl.h>
42 #include <sys/wait.h>
43
44 #include <pthread.h>
45
46 static char *app0 = "MusicOnHold";
47 static char *app1 = "WaitMusicOnHold";
48 static char *app2 = "SetMusicOnHold";
49
50 static char *synopsis0 = "Play Music On Hold indefinitely";
51 static char *synopsis1 = "Wait, playing Music On Hold";
52 static char *synopsis2 = "Set default Music On Hold class";
53
54 static char *descrip0 = "MusicOnHold(class): "
55 "Plays hold music specified by class.  If omitted, the default\n"
56 "music source for the channel will be used.  Returns -1 on hangup.\n"
57 "Never returns otherwise.\n";
58
59 static char *descrip1 = "WaitMusicOnHold(delay): "
60 "Plays hold music specified number of seconds.  Returns 0 when\n"
61 "done, or -1 on hangup.  If no hold music is available, the delay will\n"
62 "still occur with no sound.\n";
63
64 static char *descrip2 = "SetMusicOnHold(class): "
65 "Sets the default class for music on hold for a given channel.  When\n"
66 "music on hold is activated, this class will be used to select which\n"
67 "music is played.\n";
68
69 struct mohclass {
70         char class[80];
71         char dir[256];
72         char miscargs[256];
73         int destroyme;
74         int pid;                /* PID of mpg123 */
75         int quiet;
76         pthread_t thread;
77         struct mohdata *members;
78         /* Source of audio */
79         int srcfd;
80         /* FD for timing source */
81         int pseudofd;
82         struct mohclass *next;
83 };
84
85 struct mohdata {
86         int pipe[2];
87         int origwfmt;
88         struct mohclass *parent;
89         struct mohdata *next;
90 };
91
92 static struct mohclass *mohclasses;
93
94 static pthread_mutex_t moh_lock = AST_MUTEX_INITIALIZER;
95
96 #define MPG_123 "/usr/bin/mpg123"
97 #define MAX_MP3S 256
98
99 static void child_handler(int sig)
100 {
101         int status;
102         if (wait4(-1,&status, WNOHANG, NULL)<1) 
103                 if (option_debug)       
104                         ast_log(LOG_DEBUG, "Huh?  Child handler, but nobody there?\n");
105 }
106
107 static int spawn_mp3(struct mohclass *class)
108 {
109         int fds[2];
110         int files;
111         char fns[MAX_MP3S][80];
112         char *argv[MAX_MP3S + 50];
113         char xargs[256];
114         char *argptr;
115         int argc;
116         DIR *dir;
117         struct dirent *de;
118         dir = opendir(class->dir);
119         if (!dir) {
120                 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
121                 return -1;
122         }
123         argv[0] = MPG_123;
124         argv[1] = "-q";
125         argv[2] = "-s";
126         argv[3] = "--mono";
127         argv[4] = "-r";
128         argv[5] = "8000";
129         argv[6] = "-b";
130         argv[7] = "2048";
131         argc = 8;
132         if (class->quiet) {
133                 argv[argc++] = "-f";
134                 argv[argc++] = "8192";
135         }
136
137         /* Look for extra arguments and add them to the list */
138         strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
139         argptr = xargs;
140         while(argptr && strlen(argptr)) {
141                 argv[argc++] = argptr;
142                 argptr = strchr(argptr, ',');
143                 if (argptr) {
144                         *argptr = '\0';
145                         argptr++;
146                 }
147         }
148
149         files = 0;
150         while((de = readdir(dir)) && (files < MAX_MP3S)) {
151                 if ((strlen(de->d_name) > 3) && !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3")) {
152                         strncpy(fns[files], de->d_name, sizeof(fns[files]));
153                         argv[argc++] = fns[files];
154                         files++;
155                 }
156         }
157         argv[argc] = NULL;
158         closedir(dir);
159         if (pipe(fds)) {        
160                 ast_log(LOG_WARNING, "Pipe failed\n");
161                 return -1;
162         }
163 #if 0
164         printf("%d files total, %d args total\n", files, argc);
165         {
166                 int x;
167                 for (x=0;argv[x];x++)
168                         printf("arg%d: %s\n", x, argv[x]);
169         }
170 #endif  
171         if (!files) {
172                 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
173                 return -1;
174         }
175         class->pid = fork();
176         if (class->pid < 0) {
177                 close(fds[0]);
178                 close(fds[1]);
179                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
180                 return -1;
181         }
182         if (!class->pid) {
183                 int x;
184                 close(fds[0]);
185                 /* Stdout goes to pipe */
186                 dup2(fds[1], STDOUT_FILENO);
187                 /* Close unused file descriptors */
188                 for (x=3;x<8192;x++)
189                         close(x);
190                 /* Child */
191                 chdir(class->dir);
192                 execv(MPG_123, argv);
193                 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
194                 exit(1);
195         } else {
196                 /* Parent */
197                 close(fds[1]);
198         }
199         return fds[0];
200 }
201
202 static void *monmp3thread(void *data)
203 {
204         struct mohclass *class = data;
205         struct mohdata *moh;
206         char buf[8192];
207         short sbuf[8192];
208         int res, res2;
209         signal(SIGCHLD, child_handler);
210         for(;/* ever */;) {
211                 /* Spawn mp3 player if it's not there */
212                 if (class->srcfd < 0)  {
213                         if ((class->srcfd = spawn_mp3(class)) < 0) {
214                                 ast_log(LOG_WARNING, "unable to spawn mp3player\n");
215                                 /* Try again later */
216                                 sleep(500);
217                         }
218                 }
219                 if (class->pseudofd > -1) {
220                         /* Pause some amount of time */
221                         res = read(class->pseudofd, buf, sizeof(buf));
222                 } else {
223                         /* otherwise just sleep (unreliable) */
224                         usleep(100000); /* Sleep 100 ms */
225                         res = 800;              /* 800 samples */
226                 }
227                 if (!class->members)
228                         continue;
229                 /* Read mp3 audio */
230                 if ((res2 = read(class->srcfd, sbuf, res * 2)) != res * 2) {
231                         if (!res2) {
232                                 close(class->srcfd);
233                                 class->srcfd = -1;
234                                 if (class->pid) {
235                                         kill(class->pid, SIGKILL);
236                                         class->pid = 0;
237                                 }
238                         } else
239                                 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, res * 2);
240                         continue;
241                 }
242                 ast_pthread_mutex_lock(&moh_lock);
243                 moh = class->members;
244                 while(moh) {
245                         /* Write data */
246                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) 
247                                 if (option_debug)
248                                     ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
249                         moh = moh->next;
250                 }
251                 pthread_mutex_unlock(&moh_lock);
252         }
253         return NULL;
254 }
255
256 static int moh0_exec(struct ast_channel *chan, void *data)
257 {
258         if (ast_moh_start(chan, data)) {
259                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
260                 return -1;
261         }
262         while(!ast_safe_sleep(chan, 10000));
263         return -1;
264 }
265
266 static int moh1_exec(struct ast_channel *chan, void *data)
267 {
268         int res;
269         if (!data || !atoi(data)) {
270                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
271                 return -1;
272         }
273         if (ast_moh_start(chan, NULL)) {
274                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
275                 return -1;
276         }
277         res = ast_safe_sleep(chan, atoi(data) * 1000);
278         ast_moh_stop(chan);
279         return res;
280 }
281
282 static int moh2_exec(struct ast_channel *chan, void *data)
283 {
284         if (!data || !strlen(data)) {
285                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
286                 return -1;
287         }
288         strncpy(chan->musicclass, data, sizeof(chan->musicclass));
289         return 0;
290 }
291
292 static struct mohclass *get_mohbyname(char *name)
293 {
294         struct mohclass *moh;
295         moh = mohclasses;
296         while(moh) {
297                 if (!strcasecmp(name, moh->class))
298                         return moh;
299                 moh = moh->next;
300         }
301         return NULL;
302 }
303
304 static struct mohdata *mohalloc(struct mohclass *cl)
305 {
306         struct mohdata *moh;
307         long flags;
308         moh = malloc(sizeof(struct mohdata));
309         if (!moh)
310                 return NULL;
311         memset(moh, 0, sizeof(struct mohdata));
312         if (pipe(moh->pipe)) {
313                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
314                 free(moh);
315                 return NULL;
316         }
317         /* Make entirely non-blocking */
318         flags = fcntl(moh->pipe[0], F_GETFL);
319         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
320         flags = fcntl(moh->pipe[1], F_GETFL);
321         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
322         moh->parent = cl;
323         moh->next = cl->members;
324         cl->members = moh;
325         return moh;
326 }
327
328 static void moh_release(struct ast_channel *chan, void *data)
329 {
330         struct mohdata *moh = data, *prev, *cur;
331         int oldwfmt;
332         ast_pthread_mutex_lock(&moh_lock);
333         /* Unlink */
334         prev = NULL;
335         cur = moh->parent->members;
336         while(cur) {
337                 if (cur == moh) {
338                         if (prev)
339                                 prev->next = cur->next;
340                         else
341                                 moh->parent->members = cur->next;
342                         break;
343                 }
344                 prev = cur;
345                 cur = cur->next;
346         }
347         ast_pthread_mutex_unlock(&moh_lock);
348         close(moh->pipe[0]);
349         close(moh->pipe[1]);
350         oldwfmt = moh->origwfmt;
351         free(moh);
352         if (chan) {
353                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
354                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %d\n", chan->name, oldwfmt);
355                 if (option_verbose > 2)
356                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
357         }
358 }
359
360 static void *moh_alloc(struct ast_channel *chan, void *params)
361 {
362         struct mohdata *res;
363         struct mohclass *class;
364         ast_pthread_mutex_lock(&moh_lock);
365         class = get_mohbyname(params);
366         if (class)
367                 res = mohalloc(class);
368         else {
369                 if (strcasecmp(params, "default"))
370                         ast_log(LOG_WARNING, "No class: %s\n", (char *)params);
371                 res = NULL;
372         }
373         ast_pthread_mutex_unlock(&moh_lock);
374         if (res) {
375                 res->origwfmt = chan->writeformat;
376                 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
377                         ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format\n", chan->name);
378                         moh_release(NULL, res);
379                         res = NULL;
380                 }
381 #if 0
382                 /* Allow writes to interrupt */
383                 chan->writeinterrupt = 1;
384 #endif          
385                 if (option_verbose > 2)
386                         ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", (char *)params, chan->name);
387         }
388         return res;
389 }
390
391 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
392 {
393         struct ast_frame f;
394         struct mohdata *moh = data;
395         short buf[640 + AST_FRIENDLY_OFFSET / 2];
396         int res;
397
398         len = samples * 2;
399         if (len > sizeof(buf)) {
400                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", sizeof(buf), len, chan->name);
401                 len = sizeof(buf);
402         }
403         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
404 #if 0
405         if (res != len) {
406                 ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
407         }
408 #endif
409         if (res > 0) {
410                 memset(&f, 0, sizeof(f));
411                 f.frametype = AST_FRAME_VOICE;
412                 f.subclass = AST_FORMAT_SLINEAR;
413                 f.mallocd = 0;
414                 f.datalen = res;
415                 f.samples = res / 2;
416                 f.data = buf + AST_FRIENDLY_OFFSET / 2;
417                 f.offset = AST_FRIENDLY_OFFSET;
418                 if (ast_write(chan, &f)< 0) {
419                         ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
420                         return -1;
421                 }
422         }
423         return 0;
424 }
425
426 static struct ast_generator mohgen = 
427 {
428         alloc: moh_alloc,
429         release: moh_release,
430         generate: moh_generate,
431 };
432
433 static int moh_register(char *classname, char *mode, char *param, char *miscargs)
434 {
435         struct mohclass *moh;
436         int x;
437         ast_pthread_mutex_lock(&moh_lock);
438         moh = get_mohbyname(classname);
439         ast_pthread_mutex_unlock(&moh_lock);
440         if (moh) {
441                 ast_log(LOG_WARNING, "Music on Hold '%s' already exists\n", classname);
442                 return -1;
443         }
444         moh = malloc(sizeof(struct mohclass));
445         if (!moh)
446                 return -1;
447         memset(moh, 0, sizeof(struct mohclass));
448
449         strncpy(moh->class, classname, sizeof(moh->class) - 1);
450         if (miscargs)
451                 strncpy(moh->miscargs, miscargs, sizeof(moh->miscargs) - 1);
452         if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "httpmp3")) {
453                 if (!strcasecmp(mode, "quietmp3"))
454                         moh->quiet = 1;
455                 strncpy(moh->dir, param, sizeof(moh->dir));
456                 moh->srcfd = -1;
457 #ifdef ZAPATA_MOH
458                 /* It's an MP3 Moh -- Open /dev/zap/pseudo for timing...  Is
459                    there a better, yet reliable way to do this? */
460                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
461                 if (moh->pseudofd < 0) {
462                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
463                 } else {
464                         x = 320;
465                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
466                 }
467 #else
468                 moh->pseudofd = -1;
469 #endif
470                 if (pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
471                         ast_log(LOG_WARNING, "Unable to create moh...\n");
472                         if (moh->pseudofd > -1)
473                                 close(moh->pseudofd);
474                         free(moh);
475                         return -1;
476                 }
477         } else {
478                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mode);
479                 free(moh);
480                 return -1;
481         }
482         ast_pthread_mutex_lock(&moh_lock);
483         moh->next = mohclasses;
484         mohclasses = moh;
485         ast_pthread_mutex_unlock(&moh_lock);
486         return 0;
487 }
488
489 int ast_moh_start(struct ast_channel *chan, char *class)
490 {
491         if (!class || !strlen(class))
492                 class = chan->musicclass;
493         if (!class || !strlen(class))
494                 class = "default";
495         return ast_activate_generator(chan, &mohgen, class);
496 }
497
498 void ast_moh_stop(struct ast_channel *chan)
499 {
500         ast_deactivate_generator(chan);
501 }
502
503 static void load_moh_classes(void)
504 {
505         struct ast_config *cfg;
506         struct ast_variable *var;
507         char *data;
508         char *args;
509         cfg = ast_load("musiconhold.conf");
510         if (cfg) {
511                 var = ast_variable_browse(cfg, "classes");
512                 while(var) {
513                         data = strchr(var->value, ':');
514                         if (data) {
515                                 *data = '\0';
516                                 data++;
517                                 args = strchr(data, ',');
518                                 if (args) {
519                                         *args = '\0';
520                                         args++;
521                                 }
522                                 moh_register(var->name, var->value, data,args);
523                         }
524                         var = var->next;
525                 }
526                 ast_destroy(cfg);
527         }
528 }
529
530 static void ast_moh_destroy(void)
531 {
532         struct mohclass *moh;
533         ast_pthread_mutex_lock(&moh_lock);
534         moh = mohclasses;
535         while(moh) {
536                 if (moh->pid) {
537                         kill(moh->pid, SIGKILL);
538                         moh->pid = 0;
539                         }
540                 moh = moh->next;
541         }
542         ast_pthread_mutex_unlock(&moh_lock);
543 }
544
545 int load_module(void)
546 {
547         int res;
548         load_moh_classes();
549         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
550         atexit(ast_moh_destroy);
551         if (!res)
552                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
553         if (!res)
554                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
555         return res;
556 }
557
558 int unload_module(void)
559 {
560         return -1;
561 }
562
563 char *description(void)
564 {
565         return "Music On Hold Resource";
566 }
567
568 int usecount(void)
569 {
570         /* Never allow Music On Hold to be unloaded
571            unresolve needed symbols in the dialer */
572 #if 0
573         int res;
574         STANDARD_USECOUNT(res);
575         return res;
576 #else
577         return 1;
578 #endif
579 }
580
581 char *key()
582 {
583         return ASTERISK_GPL_KEY;
584 }