#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 = "f450f61f60e761b3aa089ebed76ca8a5" , .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 268 of file app_mp3.c.
References ast_register_application(), and mp3_exec().
00269 { 00270 return ast_register_application(app, mp3_exec, synopsis, descrip); 00271 }
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 00160 if (ast_strlen_zero(data)) { 00161 ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n"); 00162 return -1; 00163 } 00164 00165 u = ast_module_user_add(chan); 00166 00167 if (pipe(fds)) { 00168 ast_log(LOG_WARNING, "Unable to create pipe\n"); 00169 ast_module_user_remove(u); 00170 return -1; 00171 } 00172 00173 ast_stopstream(chan); 00174 00175 owriteformat = chan->writeformat; 00176 res = ast_set_write_format(chan, AST_FORMAT_SLINEAR); 00177 if (res < 0) { 00178 ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); 00179 ast_module_user_remove(u); 00180 return -1; 00181 } 00182 00183 res = mp3play((char *)data, fds[1]); 00184 if (!strncasecmp((char *)data, "http://", 7)) { 00185 timeout = 10000; 00186 } 00187 /* Wait 1000 ms first */ 00188 next = ast_tvnow(); 00189 next.tv_sec += 1; 00190 if (res >= 0) { 00191 pid = res; 00192 /* Order is important -- there's almost always going to be mp3... we want to prioritize the 00193 user */ 00194 for (;;) { 00195 ms = ast_tvdiff_ms(next, ast_tvnow()); 00196 if (ms <= 0) { 00197 res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); 00198 if (res > 0) { 00199 myf.f.frametype = AST_FRAME_VOICE; 00200 myf.f.subclass = AST_FORMAT_SLINEAR; 00201 myf.f.datalen = res; 00202 myf.f.samples = res / 2; 00203 myf.f.mallocd = 0; 00204 myf.f.offset = AST_FRIENDLY_OFFSET; 00205 myf.f.src = __PRETTY_FUNCTION__; 00206 myf.f.delivery.tv_sec = 0; 00207 myf.f.delivery.tv_usec = 0; 00208 myf.f.data = myf.frdata; 00209 if (ast_write(chan, &myf.f) < 0) { 00210 res = -1; 00211 break; 00212 } 00213 } else { 00214 ast_log(LOG_DEBUG, "No more mp3\n"); 00215 res = 0; 00216 break; 00217 } 00218 next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000)); 00219 } else { 00220 ms = ast_waitfor(chan, ms); 00221 if (ms < 0) { 00222 ast_log(LOG_DEBUG, "Hangup detected\n"); 00223 res = -1; 00224 break; 00225 } 00226 if (ms) { 00227 f = ast_read(chan); 00228 if (!f) { 00229 ast_log(LOG_DEBUG, "Null frame == hangup() detected\n"); 00230 res = -1; 00231 break; 00232 } 00233 if (f->frametype == AST_FRAME_DTMF) { 00234 ast_log(LOG_DEBUG, "User pressed a key\n"); 00235 ast_frfree(f); 00236 res = 0; 00237 break; 00238 } 00239 ast_frfree(f); 00240 } 00241 } 00242 } 00243 } 00244 close(fds[0]); 00245 close(fds[1]); 00246 00247 if (pid > -1) 00248 kill(pid, SIGKILL); 00249 if (!res && owriteformat) 00250 ast_set_write_format(chan, owriteformat); 00251 00252 ast_module_user_remove(u); 00253 00254 return res; 00255 }
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(), pollfd::events, pollfd::fd, LOG_NOTICE, poll(), and POLLIN.
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 = 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 257 of file app_mp3.c.
References ast_module_user_hangup_all, and ast_unregister_application().
00258 { 00259 int res; 00260 00261 res = ast_unregister_application(app); 00262 00263 ast_module_user_hangup_all(); 00264 00265 return res; 00266 }
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 = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, } [static] |
const struct ast_module_info* ast_module_info = &__mod_info [static] |
char* descrip [static] |