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
00033
00034
00035 #include "asterisk.h"
00036
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00038
00039 #include <sys/time.h>
00040 #include <signal.h>
00041
00042 #include "asterisk/lock.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/frame.h"
00046 #include "asterisk/pbx.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/translate.h"
00049 #include "asterisk/app.h"
00050
00051 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
00052 #define MPG_123 "/usr/bin/mpg123"
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 static char *app = "MP3Player";
00076
00077 static int mp3play(const char *filename, int fd)
00078 {
00079 int res;
00080
00081 res = ast_safe_fork(0);
00082 if (res < 0)
00083 ast_log(LOG_WARNING, "Fork failed\n");
00084 if (res) {
00085 return res;
00086 }
00087 if (ast_opt_high_priority)
00088 ast_set_priority(0);
00089
00090 dup2(fd, STDOUT_FILENO);
00091 ast_close_fds_above_n(STDERR_FILENO);
00092
00093
00094 if (!strncasecmp(filename, "http://", 7)) {
00095
00096 execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00097
00098 execl(MPG_123, "mpg123", "-q", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00099
00100 execlp("mpg123", "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00101 }
00102 else if (strstr(filename, ".m3u")) {
00103
00104 execl(LOCAL_MPG_123, "mpg123", "-q", "-z", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", "-@", filename, (char *)NULL);
00105
00106 execl(MPG_123, "mpg123", "-q", "-z", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", "-@", filename, (char *)NULL);
00107
00108 execlp("mpg123", "mpg123", "-q", "-z", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", "-@", filename, (char *)NULL);
00109 }
00110 else {
00111
00112 execl(MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00113
00114 execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00115
00116 execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
00117 }
00118
00119 fprintf(stderr, "Execute of mpg123 failed\n");
00120 _exit(0);
00121 }
00122
00123 static int timed_read(int fd, void *data, int datalen, int timeout)
00124 {
00125 int res;
00126 struct pollfd fds[1];
00127 fds[0].fd = fd;
00128 fds[0].events = POLLIN;
00129 res = ast_poll(fds, 1, timeout);
00130 if (res < 1) {
00131 ast_log(LOG_NOTICE, "Poll timed out/errored out with %d\n", res);
00132 return -1;
00133 }
00134 return read(fd, data, datalen);
00135
00136 }
00137
00138 static int mp3_exec(struct ast_channel *chan, const char *data)
00139 {
00140 int res=0;
00141 int fds[2];
00142 int ms = -1;
00143 int pid = -1;
00144 int owriteformat;
00145 int timeout = 2000;
00146 struct timeval next;
00147 struct ast_frame *f;
00148 struct myframe {
00149 struct ast_frame f;
00150 char offset[AST_FRIENDLY_OFFSET];
00151 short frdata[160];
00152 } myf = {
00153 .f = { 0, },
00154 };
00155
00156 if (ast_strlen_zero(data)) {
00157 ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n");
00158 return -1;
00159 }
00160
00161 if (pipe(fds)) {
00162 ast_log(LOG_WARNING, "Unable to create pipe\n");
00163 return -1;
00164 }
00165
00166 ast_stopstream(chan);
00167
00168 owriteformat = chan->writeformat;
00169 res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
00170 if (res < 0) {
00171 ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
00172 return -1;
00173 }
00174
00175 res = mp3play(data, fds[1]);
00176 if (!strncasecmp(data, "http://", 7)) {
00177 timeout = 10000;
00178 }
00179
00180 next = ast_tvnow();
00181 next.tv_sec += 1;
00182 if (res >= 0) {
00183 pid = res;
00184
00185
00186 for (;;) {
00187 ms = ast_tvdiff_ms(next, ast_tvnow());
00188 if (ms <= 0) {
00189 res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout);
00190 if (res > 0) {
00191 myf.f.frametype = AST_FRAME_VOICE;
00192 myf.f.subclass.codec = AST_FORMAT_SLINEAR;
00193 myf.f.datalen = res;
00194 myf.f.samples = res / 2;
00195 myf.f.mallocd = 0;
00196 myf.f.offset = AST_FRIENDLY_OFFSET;
00197 myf.f.src = __PRETTY_FUNCTION__;
00198 myf.f.delivery.tv_sec = 0;
00199 myf.f.delivery.tv_usec = 0;
00200 myf.f.data.ptr = myf.frdata;
00201 if (ast_write(chan, &myf.f) < 0) {
00202 res = -1;
00203 break;
00204 }
00205 } else {
00206 ast_debug(1, "No more mp3\n");
00207 res = 0;
00208 break;
00209 }
00210 next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
00211 } else {
00212 ms = ast_waitfor(chan, ms);
00213 if (ms < 0) {
00214 ast_debug(1, "Hangup detected\n");
00215 res = -1;
00216 break;
00217 }
00218 if (ms) {
00219 f = ast_read(chan);
00220 if (!f) {
00221 ast_debug(1, "Null frame == hangup() detected\n");
00222 res = -1;
00223 break;
00224 }
00225 if (f->frametype == AST_FRAME_DTMF) {
00226 ast_debug(1, "User pressed a key\n");
00227 ast_frfree(f);
00228 res = 0;
00229 break;
00230 }
00231 ast_frfree(f);
00232 }
00233 }
00234 }
00235 }
00236 close(fds[0]);
00237 close(fds[1]);
00238
00239 if (pid > -1)
00240 kill(pid, SIGKILL);
00241 if (!res && owriteformat)
00242 ast_set_write_format(chan, owriteformat);
00243
00244 return res;
00245 }
00246
00247 static int unload_module(void)
00248 {
00249 return ast_unregister_application(app);
00250 }
00251
00252 static int load_module(void)
00253 {
00254 return ast_register_application_xml(app, mp3_exec);
00255 }
00256
00257 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly MP3 Application");