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