Sat Apr 26 2014 22:01:26

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 /*** MODULEINFO
00031    <support_level>extended</support_level>
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" /* use ast_config_AST_SPOOL_DIR */
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 /*** DOCUMENTATION
00048    <application name="Dictate" language="en_US">
00049       <synopsis>
00050          Virtual Dictation Machine.
00051       </synopsis>
00052       <syntax>
00053          <parameter name="base_dir" />
00054          <parameter name="filename" />
00055       </syntax>
00056       <description>
00057          <para>Start dictation machine using optional <replaceable>base_dir</replaceable> for files.</para>
00058       </description>
00059    </application>
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");