Mon Jun 27 16:50:46 2011

Asterisk developer's documentation


app_dictate.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2005, Anthony Minessale II
00005  *
00006  * Anthony Minessale II <anthmct@yahoo.com>
00007  *
00008  * Donated by Sangoma Technologies <http://www.samgoma.com>
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  * This program is free software, distributed under the terms of
00017  * the GNU General Public License Version 2. See the LICENSE file
00018  * at the top of the source tree.
00019  */
00020 
00021 /*! \file
00022  *
00023  * \brief Virtual Dictation Machine Application For Asterisk
00024  *
00025  * \author Anthony Minessale II <anthmct@yahoo.com>
00026  *
00027  * \ingroup applications
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" /* use ast_config_AST_SPOOL_DIR */
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 /*** DOCUMENTATION
00044    <application name="Dictate" language="en_US">
00045       <synopsis>
00046          Virtual Dictation Machine.
00047       </synopsis>
00048       <syntax>
00049          <parameter name="base_dir" />
00050          <parameter name="filename" />
00051       </syntax>
00052       <description>
00053          <para>Start dictation machine using optional <replaceable>base_dir</replaceable> for files.</para>
00054       </description>
00055    </application>
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");

Generated on Mon Jun 27 16:50:46 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7