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