00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 238009 $")
00035
00036 #include <string.h>
00037 #include <stdio.h>
00038 #include <signal.h>
00039 #include <stdlib.h>
00040 #include <unistd.h>
00041 #include <fcntl.h>
00042 #include <sys/time.h>
00043 #ifdef HAVE_CAP
00044 #include <sys/capability.h>
00045 #endif
00046
00047 #include "asterisk/lock.h"
00048 #include "asterisk/file.h"
00049 #include "asterisk/logger.h"
00050 #include "asterisk/channel.h"
00051 #include "asterisk/frame.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/module.h"
00054 #include "asterisk/translate.h"
00055 #include "asterisk/options.h"
00056
00057 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
00058 #define MPG_123 "/usr/bin/mpg123"
00059
00060 static char *app = "MP3Player";
00061
00062 static char *synopsis = "Play an MP3 file or stream";
00063
00064 static char *descrip =
00065 " MP3Player(location) Executes mpg123 to play the given location,\n"
00066 "which typically would be a filename or a URL. User can exit by pressing\n"
00067 "any key on the dialpad, or by hanging up.";
00068
00069
00070 static int mp3play(char *filename, int fd)
00071 {
00072 int res;
00073 int x;
00074 sigset_t fullset, oldset;
00075 #ifdef HAVE_CAP
00076 cap_t cap;
00077 #endif
00078
00079 sigfillset(&fullset);
00080 pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
00081
00082 res = fork();
00083 if (res < 0)
00084 ast_log(LOG_WARNING, "Fork failed\n");
00085 if (res) {
00086 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
00087 return res;
00088 }
00089 #ifdef HAVE_CAP
00090 cap = cap_from_text("cap_net_admin-eip");
00091
00092 if (cap_set_proc(cap)) {
00093
00094 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
00095 }
00096 cap_free(cap);
00097 #endif
00098 if (ast_opt_high_priority)
00099 ast_set_priority(0);
00100 signal(SIGPIPE, SIG_DFL);
00101 pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
00102
00103 dup2(fd, STDOUT_FILENO);
00104 for (x=STDERR_FILENO + 1;x<256;x++) {
00105 close(x);
00106 }
00107
00108 if (!strncasecmp(filename, "http://", 7)) {
00109
00110 execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00111
00112 execl(MPG_123, "mpg123", "-q", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00113
00114 execlp("mpg123", "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00115 }
00116 else {
00117
00118 execl(MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00119
00120 execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00121
00122 execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00123 }
00124 ast_log(LOG_WARNING, "Execute of mpg123 failed\n");
00125 _exit(0);
00126 }
00127
00128 static int timed_read(int fd, void *data, int datalen, int timeout)
00129 {
00130 int res;
00131 struct pollfd fds[1];
00132 fds[0].fd = fd;
00133 fds[0].events = POLLIN;
00134 res = ast_poll(fds, 1, timeout);
00135 if (res < 1) {
00136 ast_log(LOG_NOTICE, "Poll timed out/errored out with %d\n", res);
00137 return -1;
00138 }
00139 return read(fd, data, datalen);
00140
00141 }
00142
00143 static int mp3_exec(struct ast_channel *chan, void *data)
00144 {
00145 int res=0;
00146 struct ast_module_user *u;
00147 int fds[2];
00148 int ms = -1;
00149 int pid = -1;
00150 int owriteformat;
00151 int timeout = 2000;
00152 struct timeval next;
00153 struct ast_frame *f;
00154 struct myframe {
00155 struct ast_frame f;
00156 char offset[AST_FRIENDLY_OFFSET];
00157 short frdata[160];
00158 } myf = {
00159 .f = { 0, },
00160 };
00161
00162 if (ast_strlen_zero(data)) {
00163 ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n");
00164 return -1;
00165 }
00166
00167 u = ast_module_user_add(chan);
00168
00169 if (pipe(fds)) {
00170 ast_log(LOG_WARNING, "Unable to create pipe\n");
00171 ast_module_user_remove(u);
00172 return -1;
00173 }
00174
00175 ast_stopstream(chan);
00176
00177 owriteformat = chan->writeformat;
00178 res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
00179 if (res < 0) {
00180 ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
00181 ast_module_user_remove(u);
00182 return -1;
00183 }
00184
00185 res = mp3play((char *)data, fds[1]);
00186 if (!strncasecmp((char *)data, "http://", 7)) {
00187 timeout = 10000;
00188 }
00189
00190 next = ast_tvnow();
00191 next.tv_sec += 1;
00192 if (res >= 0) {
00193 pid = res;
00194
00195
00196 for (;;) {
00197 ms = ast_tvdiff_ms(next, ast_tvnow());
00198 if (ms <= 0) {
00199 res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout);
00200 if (res > 0) {
00201 myf.f.frametype = AST_FRAME_VOICE;
00202 myf.f.subclass = AST_FORMAT_SLINEAR;
00203 myf.f.datalen = res;
00204 myf.f.samples = res / 2;
00205 myf.f.mallocd = 0;
00206 myf.f.offset = AST_FRIENDLY_OFFSET;
00207 myf.f.src = __PRETTY_FUNCTION__;
00208 myf.f.delivery.tv_sec = 0;
00209 myf.f.delivery.tv_usec = 0;
00210 myf.f.data = myf.frdata;
00211 if (ast_write(chan, &myf.f) < 0) {
00212 res = -1;
00213 break;
00214 }
00215 } else {
00216 ast_log(LOG_DEBUG, "No more mp3\n");
00217 res = 0;
00218 break;
00219 }
00220 next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
00221 } else {
00222 ms = ast_waitfor(chan, ms);
00223 if (ms < 0) {
00224 ast_log(LOG_DEBUG, "Hangup detected\n");
00225 res = -1;
00226 break;
00227 }
00228 if (ms) {
00229 f = ast_read(chan);
00230 if (!f) {
00231 ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
00232 res = -1;
00233 break;
00234 }
00235 if (f->frametype == AST_FRAME_DTMF) {
00236 ast_log(LOG_DEBUG, "User pressed a key\n");
00237 ast_frfree(f);
00238 res = 0;
00239 break;
00240 }
00241 ast_frfree(f);
00242 }
00243 }
00244 }
00245 }
00246 close(fds[0]);
00247 close(fds[1]);
00248
00249 if (pid > -1)
00250 kill(pid, SIGKILL);
00251 if (!res && owriteformat)
00252 ast_set_write_format(chan, owriteformat);
00253
00254 ast_module_user_remove(u);
00255
00256 return res;
00257 }
00258
00259 static int unload_module(void)
00260 {
00261 int res;
00262
00263 res = ast_unregister_application(app);
00264
00265 ast_module_user_hangup_all();
00266
00267 return res;
00268 }
00269
00270 static int load_module(void)
00271 {
00272 return ast_register_application(app, mp3_exec, synopsis, descrip);
00273 }
00274
00275 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly MP3 Application");