#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 "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"
Include dependency graph for app_mp3.c:
Go to the source code of this file.
Defines | |
#define | LOCAL_MPG_123 "/usr/local/bin/mpg123" |
#define | MPG_123 "/usr/bin/mpg123" |
Functions | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Silly MP3 Application") | |
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 char * | app = "MP3Player" |
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" |
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Silly MP3 Application" | ||||
) |
static int load_module | ( | void | ) | [static] |
Definition at line 250 of file app_mp3.c.
References ast_register_application(), and mp3_exec().
00251 { 00252 return ast_register_application(app, mp3_exec, synopsis, descrip); 00253 }
static int mp3_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 125 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_set_write_format(), ast_stopstream(), ast_strlen_zero(), ast_tvadd(), ast_waitfor(), ast_write(), f, LOG_DEBUG, LOG_WARNING, mp3play(), offset, timed_read(), timeout, and ast_channel::writeformat.
Referenced by load_module().
00126 { 00127 int res=0; 00128 struct ast_module_user *u; 00129 int fds[2]; 00130 int ms = -1; 00131 int pid = -1; 00132 int owriteformat; 00133 int timeout = 2000; 00134 struct timeval next; 00135 struct ast_frame *f; 00136 struct myframe { 00137 struct ast_frame f; 00138 char offset[AST_FRIENDLY_OFFSET]; 00139 short frdata[160]; 00140 } myf; 00141 00142 if (ast_strlen_zero(data)) { 00143 ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n"); 00144 return -1; 00145 } 00146 00147 u = ast_module_user_add(chan); 00148 00149 if (pipe(fds)) { 00150 ast_log(LOG_WARNING, "Unable to create pipe\n"); 00151 ast_module_user_remove(u); 00152 return -1; 00153 } 00154 00155 ast_stopstream(chan); 00156 00157 owriteformat = chan->writeformat; 00158 res = ast_set_write_format(chan, AST_FORMAT_SLINEAR); 00159 if (res < 0) { 00160 ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); 00161 ast_module_user_remove(u); 00162 return -1; 00163 } 00164 00165 res = mp3play((char *)data, fds[1]); 00166 if (!strncasecmp((char *)data, "http://", 7)) { 00167 timeout = 10000; 00168 } 00169 /* Wait 1000 ms first */ 00170 next = ast_tvnow(); 00171 next.tv_sec += 1; 00172 if (res >= 0) { 00173 pid = res; 00174 /* Order is important -- there's almost always going to be mp3... we want to prioritize the 00175 user */ 00176 for (;;) { 00177 ms = ast_tvdiff_ms(next, ast_tvnow()); 00178 if (ms <= 0) { 00179 res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); 00180 if (res > 0) { 00181 myf.f.frametype = AST_FRAME_VOICE; 00182 myf.f.subclass = AST_FORMAT_SLINEAR; 00183 myf.f.datalen = res; 00184 myf.f.samples = res / 2; 00185 myf.f.mallocd = 0; 00186 myf.f.offset = AST_FRIENDLY_OFFSET; 00187 myf.f.src = __PRETTY_FUNCTION__; 00188 myf.f.delivery.tv_sec = 0; 00189 myf.f.delivery.tv_usec = 0; 00190 myf.f.data = myf.frdata; 00191 if (ast_write(chan, &myf.f) < 0) { 00192 res = -1; 00193 break; 00194 } 00195 } else { 00196 ast_log(LOG_DEBUG, "No more mp3\n"); 00197 res = 0; 00198 break; 00199 } 00200 next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000)); 00201 } else { 00202 ms = ast_waitfor(chan, ms); 00203 if (ms < 0) { 00204 ast_log(LOG_DEBUG, "Hangup detected\n"); 00205 res = -1; 00206 break; 00207 } 00208 if (ms) { 00209 f = ast_read(chan); 00210 if (!f) { 00211 ast_log(LOG_DEBUG, "Null frame == hangup() detected\n"); 00212 res = -1; 00213 break; 00214 } 00215 if (f->frametype == AST_FRAME_DTMF) { 00216 ast_log(LOG_DEBUG, "User pressed a key\n"); 00217 ast_frfree(f); 00218 res = 0; 00219 break; 00220 } 00221 ast_frfree(f); 00222 } 00223 } 00224 } 00225 } 00226 close(fds[0]); 00227 close(fds[1]); 00228 00229 if (pid > -1) 00230 kill(pid, SIGKILL); 00231 if (!res && owriteformat) 00232 ast_set_write_format(chan, owriteformat); 00233 00234 ast_module_user_remove(u); 00235 00236 return res; 00237 }
static int mp3play | ( | char * | filename, | |
int | fd | |||
) | [static] |
Definition at line 63 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().
00064 { 00065 int res; 00066 int x; 00067 sigset_t fullset, oldset; 00068 00069 sigfillset(&fullset); 00070 pthread_sigmask(SIG_BLOCK, &fullset, &oldset); 00071 00072 res = fork(); 00073 if (res < 0) 00074 ast_log(LOG_WARNING, "Fork failed\n"); 00075 if (res) { 00076 pthread_sigmask(SIG_SETMASK, &oldset, NULL); 00077 return res; 00078 } 00079 if (ast_opt_high_priority) 00080 ast_set_priority(0); 00081 signal(SIGPIPE, SIG_DFL); 00082 pthread_sigmask(SIG_UNBLOCK, &fullset, NULL); 00083 00084 dup2(fd, STDOUT_FILENO); 00085 for (x=STDERR_FILENO + 1;x<256;x++) { 00086 if (x != STDOUT_FILENO) 00087 close(x); 00088 } 00089 /* Execute mpg123, but buffer if it's a net connection */ 00090 if (!strncasecmp(filename, "http://", 7)) { 00091 /* Most commonly installed in /usr/local/bin */ 00092 execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00093 /* But many places has it in /usr/bin */ 00094 execl(MPG_123, "mpg123", "-q", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00095 /* As a last-ditch effort, try to use PATH */ 00096 execlp("mpg123", "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00097 } 00098 else { 00099 /* Most commonly installed in /usr/local/bin */ 00100 execl(MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00101 /* But many places has it in /usr/bin */ 00102 execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00103 /* As a last-ditch effort, try to use PATH */ 00104 execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); 00105 } 00106 ast_log(LOG_WARNING, "Execute of mpg123 failed\n"); 00107 _exit(0); 00108 }
static int timed_read | ( | int | fd, | |
void * | data, | |||
int | datalen, | |||
int | timeout | |||
) | [static] |
Definition at line 110 of file app_mp3.c.
References ast_log(), pollfd::events, pollfd::fd, LOG_NOTICE, poll(), and POLLIN.
Referenced by mp3_exec(), and NBScat_exec().
00111 { 00112 int res; 00113 struct pollfd fds[1]; 00114 fds[0].fd = fd; 00115 fds[0].events = POLLIN; 00116 res = poll(fds, 1, timeout); 00117 if (res < 1) { 00118 ast_log(LOG_NOTICE, "Poll timed out/errored out with %d\n", res); 00119 return -1; 00120 } 00121 return read(fd, data, datalen); 00122 00123 }
static int unload_module | ( | void | ) | [static] |
Definition at line 239 of file app_mp3.c.
References ast_module_user_hangup_all, and ast_unregister_application().
00240 { 00241 int res; 00242 00243 res = ast_unregister_application(app); 00244 00245 ast_module_user_hangup_all(); 00246 00247 return res; 00248 }
char* descrip [static] |