Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:47 2009

## 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  * \ingroup applications
    00026  */
    00027
    00028 #include <stdlib.h>
    00029 #include <stdio.h>
    00030 #include <string.h>
    00031 #include <unistd.h>
    00032 #include <sys/stat.h>   /* for mkdir */
    00033
    00034 #include "asterisk.h"
    00035
    00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 68526 $")
    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                      if (!(fs = ast_openstream(chan, path, chan->language)))
    00261                         break;
    00262                      ast_seekstream(fs, samples, SEEK_SET);
    00263                      chan->stream = NULL;
    00264                   }
    00265                   lastop = DMODE_PLAY;
    00266                }
    00267
    00268                if (!ast_test_flag(&flags, DFLAG_PAUSE)) {
    00269                   for (x = 0; x < speed; x++) {
    00270                      if ((fr = ast_readframe(fs))) {
    00271                         ast_write(chan, fr);
    00272                         samples += fr->samples;
    00273                         ast_frfree(fr);
    00274                         fr = NULL;
    00275                      } else {
    00276                         samples = 0;
    00277                         ast_seekstream(fs, 0, SEEK_SET);
    00278                      }
    00279                   }
    00280                }
    00281                break;
    00282             case DMODE_RECORD:
    00283                if (lastop != DMODE_RECORD) {
    00284                   int oflags = O_CREAT | O_WRONLY;
    00285                   if (ast_test_flag(&flags, DFLAG_PAUSE)) {
    00286                      digit = play_and_wait(chan, "dictate/record_mode", AST_DIGIT_ANY);
    00287                      if (digit == 0) {
    00288                         digit = play_and_wait(chan, "dictate/paused", AST_DIGIT_ANY);
    00289                      } else if (digit < 0) {
    00290                         break;
    00291                      }
    00292                   }
    00293                   lastop = DMODE_RECORD;
    00294                   ast_closestream(fs);
    00295                   if ( ast_test_flag(&flags, DFLAG_TRUNC)) {
    00296                      oflags |= O_TRUNC;
    00297                      digit = play_and_wait(chan, "dictate/truncating_audio", AST_DIGIT_ANY);
    00298                   } else {
    00299                      oflags |= O_APPEND;
    00300                   }
    00301                   fs = ast_writefile(path, "raw", NULL, oflags, 0, 0700);
    00302                   if (ast_test_flag(&flags, DFLAG_TRUNC)) {
    00303                      ast_seekstream(fs, 0, SEEK_SET);
    00304                      ast_clear_flag(&flags, DFLAG_TRUNC);
    00305                   } else {
    00306                      ast_seekstream(fs, 0, SEEK_END);
    00307                   }
    00308                }
    00309                if (!ast_test_flag(&flags, DFLAG_PAUSE)) {
    00310                   res = ast_writestream(fs, f);
    00311                }
    00312                break;
    00313             }
    00314
    00315          }
    00316
    00317          ast_frfree(f);
    00318       }
    00319    }
    00320    if (oldr) {
    00321       ast_set_read_format(chan, oldr);
    00322    }
    00323    LOCAL_USER_REMOVE(u);
    00324    return 0;
    00325 }
    00326
    00327 int unload_module(void)
    00328 {
    00329    int res;
    00330
    00331    res = ast_unregister_application(app);
    00332
    00333    STANDARD_HANGUP_LOCALUSERS;
    00334
    00335    return res;
    00336 }
    00337
    00338 int load_module(void)
    00339 {
    00340    return ast_register_application(app, dictate_exec, synopsis, desc);
    00341 }
    00342
    00343 char *description(void)
    00344 {
    00345    return tdesc;
    00346 }
    00347
    00348 int usecount(void)
    00349 {
    00350    int res;
    00351    STANDARD_USECOUNT(res);
    00352    return res;
    00353 }
    00354
    00355 char *key()
    00356 {
    00357    return ASTERISK_GPL_KEY;
    00358 }
    00359