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