Use find_user for existsmailbox
[asterisk/asterisk.git] / apps / app_mp3.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Silly application to play an MP3 file -- uses mpg123
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/frame.h>
19 #include <asterisk/pbx.h>
20 #include <asterisk/module.h>
21 #include <asterisk/translate.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <signal.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <pthread.h>
29 #include <sys/time.h>
30
31 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
32 #define MPG_123 "/usr/bin/mpg123"
33
34 static char *tdesc = "Silly MP3 Application";
35
36 static char *app = "MP3Player";
37
38 static char *synopsis = "Play an MP3 file or stream";
39
40 static char *descrip = 
41 "  MP3Player(location) Executes mpg123 to play the given location\n"
42 "which typically would be a  filename  or  a URL. Returns  -1  on\n"
43 "hangup or 0 otherwise. User can exit by pressing any key\n.";
44
45 STANDARD_LOCAL_USER;
46
47 LOCAL_USER_DECL;
48
49 static int mp3play(char *filename, int fd)
50 {
51         int res;
52         int x;
53         res = fork();
54         if (res < 0) 
55                 ast_log(LOG_WARNING, "Fork failed\n");
56         if (res)
57                 return res;
58         dup2(fd, STDOUT_FILENO);
59         for (x=0;x<256;x++) {
60                 if (x != STDOUT_FILENO)
61                         close(x);
62         }
63         /* Execute mpg123, but buffer if it's a net connection */
64         if (!strncmp(filename, "http://", 7)) {
65                 /* Most commonly installed in /usr/local/bin */
66             execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
67                 /* But many places has it in /usr/bin */
68             execl(MPG_123, "mpg123", "-q", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
69                 /* As a last-ditch effort, try to use PATH */
70             execlp("mpg123", "mpg123", "-q", "-s", "-b", "1024",  "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
71         }
72         else {
73                 /* Most commonly installed in /usr/local/bin */
74             execl(MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
75                 /* But many places has it in /usr/bin */
76             execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
77                 /* As a last-ditch effort, try to use PATH */
78             execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
79         }
80         ast_log(LOG_WARNING, "Execute of mpg123 failed\n");
81         return -1;
82 }
83
84 static int timed_read(int fd, void *data, int datalen)
85 {
86         int res;
87         struct pollfd fds[1];
88         fds[0].fd = fd;
89         fds[0].events = POLLIN;
90         res = poll(fds, 1, 2000);
91         if (res < 1) {
92                 ast_log(LOG_NOTICE, "Selected timed out/errored out with %d\n", res);
93                 return -1;
94         }
95         return read(fd, data, datalen);
96         
97 }
98
99 static int mp3_exec(struct ast_channel *chan, void *data)
100 {
101         int res=0;
102         struct localuser *u;
103         int fds[2];
104         int ms = -1;
105         int pid = -1;
106         int owriteformat;
107         struct timeval now, next;
108         struct ast_frame *f;
109         struct myframe {
110                 struct ast_frame f;
111                 char offset[AST_FRIENDLY_OFFSET];
112                 short frdata[160];
113         } myf;
114
115         if (!data) {
116                 ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n");
117                 return -1;
118         }
119         if (pipe(fds)) {
120                 ast_log(LOG_WARNING, "Unable to create pipe\n");
121                 return -1;
122         }
123         LOCAL_USER_ADD(u);
124         ast_stopstream(chan);
125
126         owriteformat = chan->writeformat;
127         res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
128         if (res < 0) {
129                 ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
130                 return -1;
131         }
132         
133         gettimeofday(&now, NULL);
134         res = mp3play((char *)data, fds[1]);
135         /* Wait 1000 ms first */
136         next = now;
137         next.tv_sec += 1;
138         if (res >= 0) {
139                 pid = res;
140                 /* Order is important -- there's almost always going to be mp3...  we want to prioritize the
141                    user */
142                 for (;;) {
143                         gettimeofday(&now, NULL);
144                         ms = (next.tv_sec - now.tv_sec) * 1000;
145                         ms += (next.tv_usec - now.tv_usec) / 1000;
146 #if 0
147                         printf("ms: %d\n", ms);
148 #endif                  
149                         if (ms <= 0) {
150 #if 0
151                                 {
152                                         static struct timeval last;
153                                         struct timeval tv;
154                                         gettimeofday(&tv, NULL);
155                                         printf("Since last: %ld\n", (tv.tv_sec - last.tv_sec) * 1000 + (tv.tv_usec - last.tv_usec) / 1000);
156                                         last = tv;
157                                 }
158 #endif
159                                 res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata));
160                                 if (res > 0) {
161                                         myf.f.frametype = AST_FRAME_VOICE;
162                                         myf.f.subclass = AST_FORMAT_SLINEAR;
163                                         myf.f.datalen = res;
164                                         myf.f.samples = res / 2;
165                                         myf.f.mallocd = 0;
166                                         myf.f.offset = AST_FRIENDLY_OFFSET;
167                                         myf.f.src = __PRETTY_FUNCTION__;
168                                         myf.f.delivery.tv_sec = 0;
169                                         myf.f.delivery.tv_usec = 0;
170                                         myf.f.data = myf.frdata;
171                                         if (ast_write(chan, &myf.f) < 0) {
172                                                 res = -1;
173                                                 break;
174                                         }
175                                 } else {
176                                         ast_log(LOG_DEBUG, "No more mp3\n");
177                                         res = 0;
178                                         break;
179                                 }
180                                 next.tv_usec += res / 2 * 125;
181                                 if (next.tv_usec >= 1000000) {
182                                         next.tv_usec -= 1000000;
183                                         next.tv_sec++;
184                                 }
185 #if 0
186                                 printf("Next: %d\n", ms);
187 #endif                          
188                         } else {
189                                 ms = ast_waitfor(chan, ms);
190                                 if (ms < 0) {
191                                         ast_log(LOG_DEBUG, "Hangup detected\n");
192                                         res = -1;
193                                         break;
194                                 }
195                                 if (ms) {
196                                         f = ast_read(chan);
197                                         if (!f) {
198                                                 ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
199                                                 res = -1;
200                                                 break;
201                                         }
202                                         if (f->frametype == AST_FRAME_DTMF) {
203                                                 ast_log(LOG_DEBUG, "User pressed a key\n");
204                                                 ast_frfree(f);
205                                                 res = 0;
206                                                 break;
207                                         }
208                                         ast_frfree(f);
209                                 } 
210                         }
211                 }
212         }
213         close(fds[0]);
214         close(fds[1]);
215         LOCAL_USER_REMOVE(u);
216         if (pid > -1)
217                 kill(pid, SIGKILL);
218         if (!res && owriteformat)
219                 ast_set_write_format(chan, owriteformat);
220         return res;
221 }
222
223 int unload_module(void)
224 {
225         STANDARD_HANGUP_LOCALUSERS;
226         return ast_unregister_application(app);
227 }
228
229 int load_module(void)
230 {
231         return ast_register_application(app, mp3_exec, synopsis, descrip);
232 }
233
234 char *description(void)
235 {
236         return tdesc;
237 }
238
239 int usecount(void)
240 {
241         int res;
242         STANDARD_USECOUNT(res);
243         return res;
244 }
245
246 char *key()
247 {
248         return ASTERISK_GPL_KEY;
249 }