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