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 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 174946 $")
00033
00034 #include <sys/stat.h>
00035
00036 #include "asterisk/paths.h"
00037 #include "asterisk/file.h"
00038 #include "asterisk/pbx.h"
00039 #include "asterisk/module.h"
00040 #include "asterisk/say.h"
00041 #include "asterisk/app.h"
00042
00043 static char *app = "Dictate";
00044 static char *synopsis = "Virtual Dictation Machine";
00045 static char *desc = " Dictate([<base_dir>[,<filename>]])\n"
00046 "Start dictation machine using optional base dir for files.\n";
00047
00048
00049 typedef enum {
00050 DFLAG_RECORD = (1 << 0),
00051 DFLAG_PLAY = (1 << 1),
00052 DFLAG_TRUNC = (1 << 2),
00053 DFLAG_PAUSE = (1 << 3),
00054 } dflags;
00055
00056 typedef enum {
00057 DMODE_INIT,
00058 DMODE_RECORD,
00059 DMODE_PLAY
00060 } dmodes;
00061
00062 #define ast_toggle_flag(it,flag) if(ast_test_flag(it, flag)) ast_clear_flag(it, flag); else ast_set_flag(it, flag)
00063
00064 static int play_and_wait(struct ast_channel *chan, char *file, char *digits)
00065 {
00066 int res = -1;
00067 if (!ast_streamfile(chan, file, chan->language)) {
00068 res = ast_waitstream(chan, digits);
00069 }
00070 return res;
00071 }
00072
00073 static int dictate_exec(struct ast_channel *chan, void *data)
00074 {
00075 char *path = NULL, filein[256], *filename = "";
00076 char *parse;
00077 AST_DECLARE_APP_ARGS(args,
00078 AST_APP_ARG(base);
00079 AST_APP_ARG(filename);
00080 );
00081 char dftbase[256];
00082 char *base;
00083 struct ast_flags flags = {0};
00084 struct ast_filestream *fs;
00085 struct ast_frame *f = NULL;
00086 int ffactor = 320 * 80,
00087 res = 0,
00088 done = 0,
00089 oldr = 0,
00090 lastop = 0,
00091 samples = 0,
00092 speed = 1,
00093 digit = 0,
00094 len = 0,
00095 maxlen = 0,
00096 mode = 0;
00097
00098 snprintf(dftbase, sizeof(dftbase), "%s/dictate", ast_config_AST_SPOOL_DIR);
00099 if (!ast_strlen_zero(data)) {
00100 parse = ast_strdupa(data);
00101 AST_STANDARD_APP_ARGS(args, parse);
00102 } else
00103 args.argc = 0;
00104
00105 if (args.argc && !ast_strlen_zero(args.base)) {
00106 base = args.base;
00107 } else {
00108 base = dftbase;
00109 }
00110 if (args.argc > 1 && args.filename) {
00111 filename = args.filename;
00112 }
00113 oldr = chan->readformat;
00114 if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)) < 0) {
00115 ast_log(LOG_WARNING, "Unable to set to linear mode.\n");
00116 return -1;
00117 }
00118
00119 if (chan->_state != AST_STATE_UP) {
00120 ast_answer(chan);
00121 }
00122 ast_safe_sleep(chan, 200);
00123 for (res = 0; !res;) {
00124 if (ast_strlen_zero(filename)) {
00125 if (ast_app_getdata(chan, "dictate/enter_filename", filein, sizeof(filein), 0) ||
00126 ast_strlen_zero(filein)) {
00127 res = -1;
00128 break;
00129 }
00130 } else {
00131 ast_copy_string(filein, filename, sizeof(filein));
00132 filename = "";
00133 }
00134 ast_mkdir(base, 0755);
00135 len = strlen(base) + strlen(filein) + 2;
00136 if (!path || len > maxlen) {
00137 path = alloca(len);
00138 memset(path, 0, len);
00139 maxlen = len;
00140 } else {
00141 memset(path, 0, maxlen);
00142 }
00143
00144 snprintf(path, len, "%s/%s", base, filein);
00145 fs = ast_writefile(path, "raw", NULL, O_CREAT|O_APPEND, 0, AST_FILE_MODE);
00146 mode = DMODE_PLAY;
00147 memset(&flags, 0, sizeof(flags));
00148 ast_set_flag(&flags, DFLAG_PAUSE);
00149 digit = play_and_wait(chan, "dictate/forhelp", AST_DIGIT_ANY);
00150 done = 0;
00151 speed = 1;
00152 res = 0;
00153 lastop = 0;
00154 samples = 0;
00155 while (!done && ((res = ast_waitfor(chan, -1)) > -1) && fs && (f = ast_read(chan))) {
00156 if (digit) {
00157 struct ast_frame fr = {AST_FRAME_DTMF, digit};
00158 ast_queue_frame(chan, &fr);
00159 digit = 0;
00160 }
00161 if ((f->frametype == AST_FRAME_DTMF)) {
00162 int got = 1;
00163 switch(mode) {
00164 case DMODE_PLAY:
00165 switch(f->subclass) {
00166 case '1':
00167 ast_set_flag(&flags, DFLAG_PAUSE);
00168 mode = DMODE_RECORD;
00169 break;
00170 case '2':
00171 speed++;
00172 if (speed > 4) {
00173 speed = 1;
00174 }
00175 res = ast_say_number(chan, speed, AST_DIGIT_ANY, chan->language, NULL);
00176 break;
00177 case '7':
00178 samples -= ffactor;
00179 if(samples < 0) {
00180 samples = 0;
00181 }
00182 ast_seekstream(fs, samples, SEEK_SET);
00183 break;
00184 case '8':
00185 samples += ffactor;
00186 ast_seekstream(fs, samples, SEEK_SET);
00187 break;
00188
00189 default:
00190 got = 0;
00191 }
00192 break;
00193 case DMODE_RECORD:
00194 switch(f->subclass) {
00195 case '1':
00196 ast_set_flag(&flags, DFLAG_PAUSE);
00197 mode = DMODE_PLAY;
00198 break;
00199 case '8':
00200 ast_toggle_flag(&flags, DFLAG_TRUNC);
00201 lastop = 0;
00202 break;
00203 default:
00204 got = 0;
00205 }
00206 break;
00207 default:
00208 got = 0;
00209 }
00210 if (!got) {
00211 switch(f->subclass) {
00212 case '#':
00213 done = 1;
00214 continue;
00215 break;
00216 case '*':
00217 ast_toggle_flag(&flags, DFLAG_PAUSE);
00218 if (ast_test_flag(&flags, DFLAG_PAUSE)) {
00219 digit = play_and_wait(chan, "dictate/pause", AST_DIGIT_ANY);
00220 } else {
00221 digit = play_and_wait(chan, mode == DMODE_PLAY ? "dictate/playback" : "dictate/record", AST_DIGIT_ANY);
00222 }
00223 break;
00224 case '0':
00225 ast_set_flag(&flags, DFLAG_PAUSE);
00226 digit = play_and_wait(chan, "dictate/paused", AST_DIGIT_ANY);
00227 switch(mode) {
00228 case DMODE_PLAY:
00229 digit = play_and_wait(chan, "dictate/play_help", AST_DIGIT_ANY);
00230 break;
00231 case DMODE_RECORD:
00232 digit = play_and_wait(chan, "dictate/record_help", AST_DIGIT_ANY);
00233 break;
00234 }
00235 if (digit == 0) {
00236 digit = play_and_wait(chan, "dictate/both_help", AST_DIGIT_ANY);
00237 } else if (digit < 0) {
00238 done = 1;
00239 break;
00240 }
00241 break;
00242 }
00243 }
00244
00245 } else if (f->frametype == AST_FRAME_VOICE) {
00246 switch(mode) {
00247 struct ast_frame *fr;
00248 int x;
00249 case DMODE_PLAY:
00250 if (lastop != DMODE_PLAY) {
00251 if (ast_test_flag(&flags, DFLAG_PAUSE)) {
00252 digit = play_and_wait(chan, "dictate/playback_mode", AST_DIGIT_ANY);
00253 if (digit == 0) {
00254 digit = play_and_wait(chan, "dictate/paused", AST_DIGIT_ANY);
00255 } else if (digit < 0) {
00256 break;
00257 }
00258 }
00259 if (lastop != DFLAG_PLAY) {
00260 lastop = DFLAG_PLAY;
00261 ast_closestream(fs);
00262 if (!(fs = ast_openstream(chan, path, chan->language)))
00263 break;
00264 ast_seekstream(fs, samples, SEEK_SET);
00265 chan->stream = NULL;
00266 }
00267 lastop = DMODE_PLAY;
00268 }
00269
00270 if (!ast_test_flag(&flags, DFLAG_PAUSE)) {
00271 for (x = 0; x < speed; x++) {
00272 if ((fr = ast_readframe(fs))) {
00273 ast_write(chan, fr);
00274 samples += fr->samples;
00275 ast_frfree(fr);
00276 fr = NULL;
00277 } else {
00278 samples = 0;
00279 ast_seekstream(fs, 0, SEEK_SET);
00280 }
00281 }
00282 }
00283 break;
00284 case DMODE_RECORD:
00285 if (lastop != DMODE_RECORD) {
00286 int oflags = O_CREAT | O_WRONLY;
00287 if (ast_test_flag(&flags, DFLAG_PAUSE)) {
00288 digit = play_and_wait(chan, "dictate/record_mode", AST_DIGIT_ANY);
00289 if (digit == 0) {
00290 digit = play_and_wait(chan, "dictate/paused", AST_DIGIT_ANY);
00291 } else if (digit < 0) {
00292 break;
00293 }
00294 }
00295 lastop = DMODE_RECORD;
00296 ast_closestream(fs);
00297 if ( ast_test_flag(&flags, DFLAG_TRUNC)) {
00298 oflags |= O_TRUNC;
00299 digit = play_and_wait(chan, "dictate/truncating_audio", AST_DIGIT_ANY);
00300 } else {
00301 oflags |= O_APPEND;
00302 }
00303 fs = ast_writefile(path, "raw", NULL, oflags, 0, AST_FILE_MODE);
00304 if (ast_test_flag(&flags, DFLAG_TRUNC)) {
00305 ast_seekstream(fs, 0, SEEK_SET);
00306 ast_clear_flag(&flags, DFLAG_TRUNC);
00307 } else {
00308 ast_seekstream(fs, 0, SEEK_END);
00309 }
00310 }
00311 if (!ast_test_flag(&flags, DFLAG_PAUSE)) {
00312 res = ast_writestream(fs, f);
00313 }
00314 break;
00315 }
00316
00317 }
00318
00319 ast_frfree(f);
00320 }
00321 }
00322 if (oldr) {
00323 ast_set_read_format(chan, oldr);
00324 }
00325 return 0;
00326 }
00327
00328 static int unload_module(void)
00329 {
00330 int res;
00331 res = ast_unregister_application(app);
00332 return res;
00333 }
00334
00335 static int load_module(void)
00336 {
00337 return ast_register_application(app, dictate_exec, synopsis, desc);
00338 }
00339
00340 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Virtual Dictation Machine");