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