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