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