Fri Aug 24 02:22:10 2007

Asterisk developer's documentation


app_mwanalyze.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Digital Analyzer for Milliwatt Application
00005  * Mwanalyze 1.0
00006  * 
00007  * Copyright (C) 2006, Roger Schreiter
00008  *
00009  * Roger Schreiter <roger@planinternet.de>
00010  *
00011  * This program is free software, distributed under the terms of
00012  * the GNU General Public License
00013  */
00014 #include <asterisk.h>
00015 
00016 #include <stdio.h>
00017 #include <asterisk/file.h>
00018 #include <asterisk/logger.h>
00019 #include <asterisk/channel.h>
00020 #include <asterisk/pbx.h>
00021 #include <asterisk/module.h>
00022 #include <asterisk/lock.h>
00023 #include <stdlib.h>
00024 #include <unistd.h>
00025 #include <string.h>
00026 #include <math.h>
00027 
00028 #ifndef PI
00029 #define PI (4*atan(1))
00030 #endif
00031 
00032 static char *app = "Mwanalyze";
00033 static char *synopsis = "Spectral analyses based on a given frequency (slin)";
00034 static char *tdescription =
00035    "Mwanalyze(frequency|timeslice|duration|treshold): Analyzes audio stream for tone of given frequency.\n"
00036    "It computes the amplitude, the average ripple per timeslice, and the number of\n"
00037    "timeslices with ripple greater then given treshold.\n"
00038    "frequency is an integer divisible by 4 read as divider of 8 kHz (thus max frequency is 2 kHz).\n"
00039    "timeslice is an integer read in units of 1/8000 sec.\n"
00040    "duration is an integer read in units of timeslice.\n"
00041    "treshold is an integer meaning units of slin.\n"
00042    "Example: Mwanalyze(8|8000|60|328) will examine a 1000 Hz tone for a minute and\n"
00043    "reporting e.g. how many seconds had a ripple of more then 1% of slin's fullscale.\n" "When application is terminated, read channel variables mwa_ampitude, mwa_ripple, and mwa_bad_timeslices!\n";
00044 
00045 static int mwanalyze_exec(struct ast_channel *chan, void *data)
00046 {
00047    int res = 0;
00048    struct ast_module_user *u;
00049    char *args, *cp, *cp0, linebuf[320];
00050    unsigned int frequency = 0, timeslice = 0, duration = 0, j;
00051    int i, v, treshold = 0;
00052 
00053    int original_read_fmt;
00054    int original_write_fmt;
00055    struct ast_frame *inf = NULL;
00056    struct ast_frame outf;
00057    unsigned char waste[AST_FRIENDLY_OFFSET]; /* seen in app_millitwatt.c, don't understand what this is useful for */
00058    short buf[640];
00059    unsigned int indexp, len, ts_index, ts_offset, phase;
00060    short sin_x, cos_x, val;
00061    long long sum_sin, sum_cos, total_deviation = 0, sum_sin0 = 0, sum_cos0 = 0;
00062    int total_samples, *periods_in_timeslice, total_bad_timeslices;
00063    double coeff_sin, coeff_cos, amplitude, timeslice_ripple, total_ripple, modell_val, avg_val;
00064    short *tone, *lastperiod;
00065    long long *avg_period;
00066 
00067 
00068    /*** check whether arguments are provided ... */
00069 
00070    if ((data == NULL) || (!((char *) data)[0])) {
00071       ast_log(LOG_WARNING, "Mwanalyze needs arguments frequency, timeslice, duration and treshold.\n");
00072       return -1;
00073    }
00074 
00075    if ((args = (char *) malloc(strlen((char *) data))) == NULL) {
00076       ast_log(LOG_WARNING, "Mwanalyze cannot allocate enough memory.\n");
00077       return -1;
00078    }
00079 
00080    /*** now parse arguments ... */
00081    strcpy(args, (char *) data);
00082    cp = args;
00083    for (i = 0; i < 4; i++) {
00084       cp0 = cp;
00085       cp = strchr(cp, '|');
00086       if (cp) {
00087          *cp++ = 0;
00088       } else if (i < 3) {
00089          ast_log(LOG_WARNING, "Mwanalyze needs arguments frequency, timeslice, duration and treshold.\n");
00090          free(args);
00091          return -1;
00092       }
00093 
00094       if (sscanf(cp0, "%d", &v) != 1) {
00095          ast_log(LOG_WARNING, "Mwanalyze needs only integers as arguments.\n");
00096          free(args);
00097          return -1;
00098       }
00099 
00100       switch (i) {
00101          case 0:
00102             frequency = v;
00103          case 1:
00104             timeslice = v;
00105          case 2:
00106             duration = v;
00107          case 3:
00108             treshold = v;
00109       }
00110    }
00111 
00112    /*** prepare sine wave */
00113    if (frequency % 4)
00114       frequency--;
00115    if (frequency % 4)
00116       frequency--;
00117    if (frequency % 4)
00118       frequency--;
00119    if (frequency < 4) {
00120       frequency = 4;
00121    }
00122    if (timeslice < frequency) {
00123       timeslice = frequency;
00124    }
00125    if (duration < 1) {
00126       duration = 1;
00127    }
00128    if (treshold < 1) {
00129       treshold = 1;
00130    }
00131 
00132    if ((tone = (short *) malloc(frequency * sizeof(short))) == NULL) {
00133       ast_log(LOG_WARNING, "Mwanalyze cannot allocate enough memory.\n");
00134       free(args);
00135       return -1;
00136    }
00137    if ((lastperiod = (short *) malloc(frequency * sizeof(short))) == NULL) {
00138       ast_log(LOG_WARNING, "Mwanalyze cannot allocate enough memory.\n");
00139       free(tone);
00140       free(args);
00141       return -1;
00142    }
00143    if ((avg_period = (long long *) malloc(frequency * sizeof(long long))) == NULL) {
00144       ast_log(LOG_WARNING, "Mwanalyze cannot allocate enough memory.\n");
00145       free(lastperiod);
00146       free(tone);
00147       free(args);
00148       return -1;
00149    }
00150    if ((periods_in_timeslice = (int *) malloc(frequency * sizeof(int))) == NULL) {
00151       ast_log(LOG_WARNING, "Mwanalyze cannot allocate enough memory.\n");
00152       free(avg_period);
00153       free(lastperiod);
00154       free(tone);
00155       free(args);
00156       return -1;
00157    }
00158 
00159    for (indexp = 0; indexp < frequency; indexp++) {
00160       tone[indexp] = (short) (sin((double) indexp / frequency * 2 * PI) * ((1 << 15) - 1));
00161    }
00162 
00163    u = ast_module_user_add(chan);
00164 
00165    /*** answer if necessary */
00166    if ((!res) && (chan->_state != AST_STATE_UP)) {
00167       if ((res = ast_answer(chan)) < 0) {
00168          ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
00169       }
00170    }
00171 
00172    /*** save audio codecs and switch to slin if necessary */
00173    original_read_fmt = AST_FORMAT_SLINEAR;
00174    if ((!res) && ((original_read_fmt = chan->readformat) != AST_FORMAT_SLINEAR)) {
00175       if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)) < 0) {
00176          ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up.\n");
00177       }
00178    }
00179    original_write_fmt = AST_FORMAT_SLINEAR;
00180    if ((!res) && ((original_write_fmt = chan->writeformat) != AST_FORMAT_SLINEAR)) {
00181       if ((res = ast_set_write_format(chan, AST_FORMAT_SLINEAR)) < 0) {
00182          ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up.\n");
00183       }
00184    }
00185 
00186 
00187    ts_index = 0;
00188    ts_offset = 0;
00189    phase = 0;
00190    sum_sin = sum_cos = 0.0;
00191    total_samples = 0;
00192    total_ripple = 0.0;
00193    total_bad_timeslices = 0;
00194 
00195    while ((ts_index < duration) && (!res) && (ast_waitfor(chan, -1) > -1)) {
00196       if ((inf = ast_read(chan)) == NULL) {
00197          /*** got hangup */
00198          res = -1;
00199          break;
00200       }
00201 
00202       if (inf->frametype == AST_FRAME_VOICE) {
00203          len = inf->samples;
00204          if (len > sizeof(buf)) {
00205             ast_log(LOG_WARNING, "Can only exchange %d bytes.\n", (int) sizeof(buf));
00206             len = sizeof(buf);
00207          }
00208 
00209          /*** analyze */
00210          for (i = 0; i < (int) len; i++) {
00211             /*** Fourier */
00212             val = ((short *) inf->data)[i];
00213             sin_x = tone[phase];
00214             cos_x = tone[(phase < 3 * frequency / 4) ? (phase + frequency / 4) : (phase - 3 * frequency / 4)];
00215             sum_sin += sin_x * val;
00216             sum_cos += cos_x * val;
00217 
00218             /*** total deviatian from real waveshape */
00219             if (ts_offset == 0) {
00220                total_deviation = 0;
00221                sum_sin0 = sum_sin;
00222                sum_cos0 = sum_cos;
00223             }
00224             if (ts_offset >= frequency) {
00225                total_deviation += (val >= lastperiod[phase]) ? (val - lastperiod[phase]) : (lastperiod[phase] - val);
00226             } else {
00227                avg_period[phase] = 0;
00228                periods_in_timeslice[phase] = 0;
00229             }
00230             lastperiod[phase] = val;
00231             avg_period[phase] += val;
00232             periods_in_timeslice[phase]++;
00233 
00234 
00235             /*** adavance pointers */
00236             if (++ts_offset == timeslice) {
00237                timeslice_ripple = (double) total_deviation / 2 / timeslice;
00238                coeff_sin = (sum_sin - sum_sin0) * 2.0 / ((1 << 15) - 1) / timeslice;
00239                coeff_cos = (sum_cos - sum_cos0) * 2.0 / ((1 << 15) - 1) / timeslice;
00240 
00241                total_deviation = 0;
00242                for (j = 0; j < frequency; j++) {
00243                   sin_x = tone[j];
00244                   cos_x = tone[(j < 3 * frequency / 4) ? (j + frequency / 4) : (j - 3 * frequency / 4)];
00245                   modell_val = coeff_sin * sin_x / ((1 << 15) - 1) + coeff_cos * cos_x / ((1 << 15) - 1);
00246                   avg_val = (double) avg_period[j] / periods_in_timeslice[j];
00247                   total_deviation += (long long) ((avg_val >= modell_val) ? (avg_val - modell_val) : (modell_val - avg_val));
00248                }
00249                timeslice_ripple += (double) total_deviation / frequency;
00250                total_ripple += timeslice_ripple;
00251                if (timeslice_ripple > treshold) {
00252                   total_bad_timeslices++;
00253                }
00254 
00255                ts_offset = 0;
00256                ts_index++;
00257             }
00258 
00259             if (++phase == frequency) {
00260                phase = 0;
00261             }
00262             total_samples++;
00263          }
00264 
00265          waste[0] = 0;     /* ???? */
00266          outf.frametype = AST_FRAME_VOICE;
00267          outf.subclass = AST_FORMAT_SLINEAR;
00268          outf.offset = AST_FRIENDLY_OFFSET;  /* ???? */
00269          outf.mallocd = 0;
00270          outf.data = buf;
00271          outf.datalen = len * sizeof(short);
00272          outf.samples = len;
00273          outf.src = "app_mwanalyze";
00274          outf.delivery.tv_sec = 0;
00275          outf.delivery.tv_usec = 0;
00276          for (i = 0; i < (int) len; i++) {
00277             if (indexp == frequency) {
00278                indexp = 0;
00279             }
00280             buf[i] = tone[indexp++];
00281          }
00282 
00283          if ((res = ast_write(chan, &outf)) < 0) {
00284             ast_log(LOG_WARNING, "Failed to write frame to '%s'.\n", chan->name);
00285          }
00286 
00287       }
00288 
00289       ast_frfree(inf);
00290    }
00291 
00292 
00293    /*** restore audio codecs if necessary */
00294    if (original_read_fmt != AST_FORMAT_SLINEAR) {
00295       if (ast_set_read_format(chan, original_read_fmt) < 0) {
00296          ast_log(LOG_WARNING, "Unable to restore read mode.\n");
00297       }
00298    }
00299    if (original_write_fmt != AST_FORMAT_SLINEAR) {
00300       if (ast_set_write_format(chan, original_write_fmt) < 0) {
00301          ast_log(LOG_WARNING, "Unable to restore write mode.\n");
00302       }
00303    }
00304 
00305 
00306    coeff_sin = (total_samples) ? (sum_sin * 2.0 / ((1 << 15) - 1) / total_samples) : 0.0;
00307    coeff_cos = (total_samples) ? (sum_cos * 2.0 / ((1 << 15) - 1) / total_samples) : 0.0;
00308    amplitude = sqrt(coeff_sin * coeff_sin + coeff_cos * coeff_cos);
00309 
00310    sprintf(linebuf, "%lg", amplitude);
00311    pbx_builtin_setvar_helper(chan, "mwa_amplitude", linebuf);
00312    sprintf(linebuf, "%lg", (duration) ? (total_ripple / duration) : 0.0);
00313    pbx_builtin_setvar_helper(chan, "mwa_ripple", linebuf);
00314    sprintf(linebuf, "%d", total_bad_timeslices);
00315    pbx_builtin_setvar_helper(chan, "mwa_bad_timeslices", linebuf);
00316 
00317    ast_module_user_remove(u);
00318    free(periods_in_timeslice);
00319    free(avg_period);
00320    free(lastperiod);
00321    free(tone);
00322    free(args);
00323    return res;
00324 }
00325 
00326 
00327 static int unload_module(void)
00328 {
00329    int res;
00330 
00331    res = ast_unregister_application(app);
00332 
00333    ast_module_user_hangup_all();
00334 
00335    return res;
00336 }
00337 
00338 static int load_module(void)
00339 {
00340    return ast_register_application(app, mwanalyze_exec, synopsis, tdescription);
00341 }
00342 
00343 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Digital Analyzer for Milliwatt Application (slin)");

Generated on Fri Aug 24 02:22:10 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1