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: 182810 $")
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 <sys/socket.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 LOCAL_NBSCAT "/usr/local/bin/nbscat8k"
00059 #define NBSCAT "/usr/bin/nbscat8k"
00060
00061 #ifndef AF_LOCAL
00062 #define AF_LOCAL AF_UNIX
00063 #endif
00064
00065 static char *app = "NBScat";
00066
00067 static char *synopsis = "Play an NBS local stream";
00068
00069 static char *descrip =
00070 " NBScat: Executes nbscat to listen to the local NBS stream.\n"
00071 "User can exit by pressing any key\n.";
00072
00073
00074 static int NBScatplay(int fd)
00075 {
00076 int res;
00077 int x;
00078 sigset_t fullset, oldset;
00079 #ifdef HAVE_CAP
00080 cap_t cap;
00081 #endif
00082
00083 sigfillset(&fullset);
00084 pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
00085
00086 res = fork();
00087 if (res < 0)
00088 ast_log(LOG_WARNING, "Fork failed\n");
00089 if (res) {
00090 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
00091 return res;
00092 }
00093 signal(SIGPIPE, SIG_DFL);
00094 pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
00095
00096 #ifdef HAVE_CAP
00097 cap = cap_from_text("cap_net_admin-eip");
00098
00099 if (cap_set_proc(cap)) {
00100
00101 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
00102 }
00103 cap_free(cap);
00104 #endif
00105 if (ast_opt_high_priority)
00106 ast_set_priority(0);
00107
00108 dup2(fd, STDOUT_FILENO);
00109 for (x = STDERR_FILENO + 1; x < 1024; x++) {
00110 if (x != STDOUT_FILENO)
00111 close(x);
00112 }
00113
00114 execl(NBSCAT, "nbscat8k", "-d", (char *)NULL);
00115 execl(LOCAL_NBSCAT, "nbscat8k", "-d", (char *)NULL);
00116 ast_log(LOG_WARNING, "Execute of nbscat8k failed\n");
00117 _exit(0);
00118 }
00119
00120 static int timed_read(int fd, void *data, int datalen)
00121 {
00122 int res;
00123 struct pollfd fds[1];
00124 fds[0].fd = fd;
00125 fds[0].events = POLLIN;
00126 res = ast_poll(fds, 1, 2000);
00127 if (res < 1) {
00128 ast_log(LOG_NOTICE, "Selected timed out/errored out with %d\n", res);
00129 return -1;
00130 }
00131 return read(fd, data, datalen);
00132
00133 }
00134
00135 static int NBScat_exec(struct ast_channel *chan, void *data)
00136 {
00137 int res=0;
00138 struct ast_module_user *u;
00139 int fds[2];
00140 int ms = -1;
00141 int pid = -1;
00142 int owriteformat;
00143 struct timeval next;
00144 struct ast_frame *f;
00145 struct myframe {
00146 struct ast_frame f;
00147 char offset[AST_FRIENDLY_OFFSET];
00148 short frdata[160];
00149 } myf;
00150
00151 u = ast_module_user_add(chan);
00152
00153 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) {
00154 ast_log(LOG_WARNING, "Unable to create socketpair\n");
00155 ast_module_user_remove(u);
00156 return -1;
00157 }
00158
00159 ast_stopstream(chan);
00160
00161 owriteformat = chan->writeformat;
00162 res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
00163 if (res < 0) {
00164 ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
00165 ast_module_user_remove(u);
00166 return -1;
00167 }
00168
00169 res = NBScatplay(fds[1]);
00170
00171 next = ast_tvnow();
00172 next.tv_sec += 1;
00173 if (res >= 0) {
00174 pid = res;
00175
00176
00177 for (;;) {
00178 ms = ast_tvdiff_ms(next, ast_tvnow());
00179 if (ms <= 0) {
00180 res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata));
00181 if (res > 0) {
00182 myf.f.frametype = AST_FRAME_VOICE;
00183 myf.f.subclass = AST_FORMAT_SLINEAR;
00184 myf.f.datalen = res;
00185 myf.f.samples = res / 2;
00186 myf.f.mallocd = 0;
00187 myf.f.offset = AST_FRIENDLY_OFFSET;
00188 myf.f.src = __PRETTY_FUNCTION__;
00189 myf.f.delivery.tv_sec = 0;
00190 myf.f.delivery.tv_usec = 0;
00191 myf.f.data = myf.frdata;
00192 if (ast_write(chan, &myf.f) < 0) {
00193 res = -1;
00194 break;
00195 }
00196 } else {
00197 ast_log(LOG_DEBUG, "No more mp3\n");
00198 res = 0;
00199 break;
00200 }
00201 next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
00202 } else {
00203 ms = ast_waitfor(chan, ms);
00204 if (ms < 0) {
00205 ast_log(LOG_DEBUG, "Hangup detected\n");
00206 res = -1;
00207 break;
00208 }
00209 if (ms) {
00210 f = ast_read(chan);
00211 if (!f) {
00212 ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
00213 res = -1;
00214 break;
00215 }
00216 if (f->frametype == AST_FRAME_DTMF) {
00217 ast_log(LOG_DEBUG, "User pressed a key\n");
00218 ast_frfree(f);
00219 res = 0;
00220 break;
00221 }
00222 ast_frfree(f);
00223 }
00224 }
00225 }
00226 }
00227 close(fds[0]);
00228 close(fds[1]);
00229
00230 if (pid > -1)
00231 kill(pid, SIGKILL);
00232 if (!res && owriteformat)
00233 ast_set_write_format(chan, owriteformat);
00234
00235 ast_module_user_remove(u);
00236
00237 return res;
00238 }
00239
00240 static int unload_module(void)
00241 {
00242 int res;
00243
00244 res = ast_unregister_application(app);
00245
00246 ast_module_user_hangup_all();
00247
00248 return res;
00249 }
00250
00251 static int load_module(void)
00252 {
00253 return ast_register_application(app, NBScat_exec, synopsis, descrip);
00254 }
00255
00256 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly NBS Stream Application");