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