#include "asterisk.h"
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/capability.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/frame.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/options.h"
Go to the source code of this file.
Defines | |
#define | LOCAL_MPG_123 "/usr/local/bin/mpg123" |
#define | MPG_123 "/usr/bin/mpg123" |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | load_module (void) |
static int | mp3_exec (struct ast_channel *chan, void *data) |
static int | mp3play (char *filename, int fd) |
static int | timed_read (int fd, void *data, int datalen, int timeout) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Silly MP3 Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } |
static char * | app = "MP3Player" |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static char * | descrip |
static char * | synopsis = "Play an MP3 file or stream" |
Definition in file app_mp3.c.
#define LOCAL_MPG_123 "/usr/local/bin/mpg123" |
#define MPG_123 "/usr/bin/mpg123" |
static int load_module | ( | void | ) | [static] |
Definition at line 270 of file app_mp3.c.
References ast_register_application(), and mp3_exec().
00271 { 00272 return ast_register_application(app, mp3_exec, synopsis, descrip); 00273 }
static int mp3_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 143 of file app_mp3.c.
References AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, AST_FRIENDLY_OFFSET, ast_log(), ast_module_user_add, ast_module_user_remove, ast_read(), ast_samp2tv(), ast_set_write_format(), ast_stopstream(), ast_strlen_zero(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), ast_write(), f, LOG_DEBUG, LOG_WARNING, mp3play(), offset, timed_read(), and ast_channel::writeformat.
Referenced by load_module().
00144 { 00145 int res=0; 00146 struct ast_module_user *u; 00147 int fds[2]; 00148 int ms = -1; 00149 int pid = -1; 00150 int owriteformat; 00151 int timeout = 2000; 00152 struct timeval next; 00153 struct ast_frame *f; 00154 struct myframe { 00155 struct ast_frame f; 00156 char offset[AST_FRIENDLY_OFFSET]; 00157 short frdata[160]; 00158 } myf = { 00159 .f = { 0, }, 00160 }; 00161 00162 if (ast_strlen_zero(data)) { 00163 ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n"); 00164 return -1; 00165 } 00166 00167 u = ast_module_user_add(chan); 00168 00169 if (pipe(fds)) { 00170 ast_log(LOG_WARNING, "Unable to create pipe\n"); 00171 ast_module_user_remove(u); 00172 return -1; 00173 } 00174 00175 ast_stopstream(chan); 00176 00177 owriteformat = chan->writeformat; 00178 res = ast_set_write_format(chan, AST_FORMAT_SLINEAR); 00179 if (res < 0) { 00180 ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); 00181 ast_module_user_remove(u); 00182 return -1; 00183 } 00184 00185 res = mp3play((char *)data, fds[1]); 00186 if (!strncasecmp((char *)data, "http://", 7)) { 00187 timeout = 10000; 00188 } 00189 /* Wait 1000 ms first */ 00190 next = ast_tvnow(); 00191 next.tv_sec += 1; 00192 if (res >= 0) { 00193 pid = res; 00194 /* Order is important -- there's almost always going to be mp3... we want to prioritize the 00195 user */ 00196 for (;;) { 00197 ms = ast_tvdiff_ms(next, ast_tvnow()); 00198 if (ms <= 0) { 00199 res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); 00200 if (res > 0) { 00201 myf.f.frametype = AST_FRAME_VOICE; 00202 myf.f.subclass = AST_FORMAT_SLINEAR; 00203 myf.f.datalen = res; 00204 myf.f.samples = res / 2; 00205 myf.f.mallocd = 0; 00206 myf.f.offset = AST_FRIENDLY_OFFSET; 00207 myf.f.src = __PRETTY_FUNCTION__; 00208 myf.f.delivery.tv_sec = 0; 00209 myf.f.delivery.tv_usec = 0; 00210 myf.f.data = myf.frdata; 00211 if (ast_write(chan, &myf.f) < 0) { 00212 res = -1; 00213 break; 00214 } 00215 } else { 00216 ast_log(LOG_DEBUG, "No more mp3\n"); 00217 res = 0; 00218 break; 00219 } 00220 next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000)); 00221 } else { 00222 ms = ast_waitfor(chan, ms); 00223 if (ms < 0) { 00224 ast_log(LOG_DEBUG, "Hangup detected\n"); 00225 res = -1; 00226 break; 00227 } 00228 if (ms) { 00229 f = ast_read(chan); 00230 if (!f) { 00231 ast_log(LOG_DEBUG, "Null frame == hangup() detected\n"); 00232 res = -1; 00233 break; 00234 } 00235 if (f->frametype == AST_FRAME_DTMF) { 00236 ast_log(LOG_DEBUG, "User pressed a key\n"); 00237 ast_frfree(f); 00238 res = 0; 00239 break; 00240 } 00241 ast_frfree(f); 00242 } 00243 } 00244 } 00245 } 00246 close(fds[0]); 00247 close(fds[1]); 00248 00249 if (pid > -1) 00250 kill(pid, SIGKILL); 00251 if (!res && owriteformat) 00252 ast_set_write_format(chan, owriteformat); 00253 00254 ast_module_user_remove(u); 00255 00256 return res; 00257 }
static int mp3play | ( | char * | filename, | |
int | fd | |||
) | [static] |
Definition at line 70 of file app_mp3.c.
References ast_log(), ast_opt_high_priority, ast_set_priority(), LOCAL_MPG_123, LOG_WARNING, and MPG_123.
Referenced by mp3_exec().
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 #ifdef HAVE_CAP 00090 cap = cap_from_text("cap_net_admin-eip"); 00091 00092 if (cap_set_proc(cap)) { 00093 /* Careful with order! Logging cannot happen after we close FDs */ 00094 ast_log(LOG_WARNING, "Unable to remove capabilities.\n"); 00095 } 00096 cap_free(cap); 00097 #endif 00098 if (ast_opt_high_priority) 00099 ast_set_priority(0); 00100 signal(SIGPIPE, SIG_DFL); 00101 pthread_sigmask(SIG_UNBLOCK, &fullset, NULL); 00102 00103 dup2(fd, STDOUT_FILENO); 00104 for (x=STDERR_FILENO + 1;x<256;x++) { 00105 close(x); 00106 } 00107 /* Execute mpg123, but buffer if it's a net connection */ 00108 if (!strncasecmp(filename, "http://", 7)) { 00109 /* Most commonly installed in /usr/local/bin */ 00110 execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00111 /* But many places has it in /usr/bin */ 00112 execl(MPG_123, "mpg123", "-q", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00113 /* As a last-ditch effort, try to use PATH */ 00114 execlp("mpg123", "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00115 } 00116 else { 00117 /* Most commonly installed in /usr/local/bin */ 00118 execl(MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00119 /* But many places has it in /usr/bin */ 00120 execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00121 /* As a last-ditch effort, try to use PATH */ 00122 execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00123 } 00124 ast_log(LOG_WARNING, "Execute of mpg123 failed\n"); 00125 _exit(0); 00126 }
static int timed_read | ( | int | fd, | |
void * | data, | |||
int | datalen, | |||
int | timeout | |||
) | [static] |
Definition at line 128 of file app_mp3.c.
References ast_log(), ast_poll, and LOG_NOTICE.
Referenced by mp3_exec(), and NBScat_exec().
00129 { 00130 int res; 00131 struct pollfd fds[1]; 00132 fds[0].fd = fd; 00133 fds[0].events = POLLIN; 00134 res = ast_poll(fds, 1, timeout); 00135 if (res < 1) { 00136 ast_log(LOG_NOTICE, "Poll timed out/errored out with %d\n", res); 00137 return -1; 00138 } 00139 return read(fd, data, datalen); 00140 00141 }
static int unload_module | ( | void | ) | [static] |
Definition at line 259 of file app_mp3.c.
References ast_module_user_hangup_all, and ast_unregister_application().
00260 { 00261 int res; 00262 00263 res = ast_unregister_application(app); 00264 00265 ast_module_user_hangup_all(); 00266 00267 return res; 00268 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Silly MP3 Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } [static] |
const struct ast_module_info* ast_module_info = &__mod_info [static] |
char* descrip [static] |