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 #include <string.h>
00027 #include <stdio.h>
00028 #include <signal.h>
00029 #include <stdlib.h>
00030 #include <unistd.h>
00031 #include <fcntl.h>
00032 #include <sys/time.h>
00033 #include <errno.h>
00034
00035 #include "asterisk.h"
00036
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
00038
00039 #include "asterisk/lock.h"
00040 #include "asterisk/file.h"
00041 #include "asterisk/logger.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/frame.h"
00044 #include "asterisk/pbx.h"
00045 #include "asterisk/module.h"
00046 #include "asterisk/translate.h"
00047
00048 #define ICES "/usr/bin/ices"
00049 #define LOCAL_ICES "/usr/local/bin/ices"
00050
00051 static char *tdesc = "Encode and Stream via icecast and ices";
00052
00053 static char *app = "ICES";
00054
00055 static char *synopsis = "Encode and stream using 'ices'";
00056
00057 static char *descrip =
00058 " ICES(config.xml) Streams to an icecast server using ices\n"
00059 "(available separately). A configuration file must be supplied\n"
00060 "for ices (see examples/asterisk-ices.conf). \n";
00061
00062 STANDARD_LOCAL_USER;
00063
00064 LOCAL_USER_DECL;
00065
00066 static int icesencode(char *filename, int fd)
00067 {
00068 int res;
00069 int x;
00070 res = fork();
00071 if (res < 0)
00072 ast_log(LOG_WARNING, "Fork failed\n");
00073 if (res)
00074 return res;
00075 dup2(fd, STDIN_FILENO);
00076 for (x=STDERR_FILENO + 1;x<256;x++) {
00077 if ((x != STDIN_FILENO) && (x != STDOUT_FILENO))
00078 close(x);
00079 }
00080
00081 execl(ICES, "ices", filename, (char *)NULL);
00082
00083 execl(LOCAL_ICES, "ices", filename, (char *)NULL);
00084
00085 execlp("ices", "ices", filename, (char *)NULL);
00086 ast_log(LOG_WARNING, "Execute of ices failed\n");
00087 return -1;
00088 }
00089
00090 static int ices_exec(struct ast_channel *chan, void *data)
00091 {
00092 int res=0;
00093 struct localuser *u;
00094 int fds[2];
00095 int ms = -1;
00096 int pid = -1;
00097 int flags;
00098 int oreadformat;
00099 struct timeval last;
00100 struct ast_frame *f;
00101 char filename[256]="";
00102 char *c;
00103
00104 if (ast_strlen_zero(data)) {
00105 ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n");
00106 return -1;
00107 }
00108
00109 LOCAL_USER_ADD(u);
00110
00111 last = ast_tv(0, 0);
00112
00113 if (pipe(fds)) {
00114 ast_log(LOG_WARNING, "Unable to create pipe\n");
00115 LOCAL_USER_REMOVE(u);
00116 return -1;
00117 }
00118 flags = fcntl(fds[1], F_GETFL);
00119 fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
00120
00121 ast_stopstream(chan);
00122
00123 if (chan->_state != AST_STATE_UP)
00124 res = ast_answer(chan);
00125
00126 if (res) {
00127 close(fds[0]);
00128 close(fds[1]);
00129 ast_log(LOG_WARNING, "Answer failed!\n");
00130 LOCAL_USER_REMOVE(u);
00131 return -1;
00132 }
00133
00134 oreadformat = chan->readformat;
00135 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00136 if (res < 0) {
00137 close(fds[0]);
00138 close(fds[1]);
00139 ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
00140 LOCAL_USER_REMOVE(u);
00141 return -1;
00142 }
00143 if (((char *)data)[0] == '/')
00144 strncpy(filename, (char *)data, sizeof(filename) - 1);
00145 else
00146 snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, (char *)data);
00147
00148 c = strchr(filename, '|');
00149 if (c)
00150 *c = '\0';
00151 res = icesencode(filename, fds[0]);
00152 close(fds[0]);
00153 if (res >= 0) {
00154 pid = res;
00155 for (;;) {
00156
00157 ms = ast_waitfor(chan, -1);
00158 if (ms < 0) {
00159 ast_log(LOG_DEBUG, "Hangup detected\n");
00160 res = -1;
00161 break;
00162 }
00163 f = ast_read(chan);
00164 if (!f) {
00165 ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
00166 res = -1;
00167 break;
00168 }
00169 if (f->frametype == AST_FRAME_VOICE) {
00170 res = write(fds[1], f->data, f->datalen);
00171 if (res < 0) {
00172 if (errno != EAGAIN) {
00173 ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
00174 res = -1;
00175 break;
00176 }
00177 }
00178 }
00179 ast_frfree(f);
00180 }
00181 }
00182 close(fds[1]);
00183
00184 if (pid > -1)
00185 kill(pid, SIGKILL);
00186 if (!res && oreadformat)
00187 ast_set_read_format(chan, oreadformat);
00188
00189 LOCAL_USER_REMOVE(u);
00190
00191 return res;
00192 }
00193
00194 int unload_module(void)
00195 {
00196 int res;
00197
00198 res = ast_unregister_application(app);
00199
00200 STANDARD_HANGUP_LOCALUSERS;
00201
00202 return res;
00203 }
00204
00205 int load_module(void)
00206 {
00207 return ast_register_application(app, ices_exec, synopsis, descrip);
00208 }
00209
00210 char *description(void)
00211 {
00212 return tdesc;
00213 }
00214
00215 int usecount(void)
00216 {
00217 int res;
00218 STANDARD_USECOUNT(res);
00219 return res;
00220 }
00221
00222 char *key()
00223 {
00224 return ASTERISK_GPL_KEY;
00225 }