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