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