From 724fa0901a8dd167acfb0d19e4969b6099d47ac1 Mon Sep 17 00:00:00 2001 From: Armin Schindler Date: Sun, 26 Jul 1998 18:48:45 +0000 Subject: [PATCH] Added silence detection in voice receive mode. --- Documentation/isdn/README.audio | 16 +++--- drivers/isdn/isdn_audio.c | 93 +++++++++++++++++++++++++++++++++ drivers/isdn/isdn_audio.h | 11 ++++ drivers/isdn/isdn_tty.c | 58 +++++++++++--------- include/linux/isdn.h | 6 +++ 5 files changed, 153 insertions(+), 31 deletions(-) diff --git a/Documentation/isdn/README.audio b/Documentation/isdn/README.audio index 8eed482b..93d5789d 100644 --- a/Documentation/isdn/README.audio +++ b/Documentation/isdn/README.audio @@ -50,10 +50,11 @@ The following commands are supported: the application. See below for data format AT+VSD=x,y Set silence-detection parameters. - NO EFFECT, supported for compatibility - only. Possible parameters: - x = 0 ... 31 - y = 0 ... 255 + Possible parameters: + x = 0 ... 31 sensitivity threshold level. + (default 0 , deactivated) + y = 0 ... 255 range of interval in units + of 0.1 second. (default 70) AT+VSD=? Report possible parameters. AT+VSD? Show current parameters. @@ -102,13 +103,14 @@ General behavior and description of data formats/protocol. C Touchtone "C" received. D Touchtone "D" received. + q quiet. Silence detected after non-silence. + s silence. Silence detected from the + start of recording. + Currently unsupported DLE sequences: c FAX calling tone received. b busy tone received. - q quiet. Silence detected after non-silence. - s silence. Silence detected from the - start of recording. Audio playback. diff --git a/drivers/isdn/isdn_audio.c b/drivers/isdn/isdn_audio.c index 544609b8..4c49dbd9 100644 --- a/drivers/isdn/isdn_audio.c +++ b/drivers/isdn/isdn_audio.c @@ -4,6 +4,7 @@ * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at) + * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log$ + * Revision 1.11 1998/04/10 10:35:10 paul + * fixed (silly?) warnings from egcs on Alpha. + * * Revision 1.10 1998/02/20 17:09:40 fritz * Changes for recent kernels. * @@ -660,3 +664,92 @@ isdn_audio_calc_dtmf(modem_info * info, unsigned char *buf, int len, int fmt) len -= c; } } + +silence_state * +isdn_audio_silence_init(silence_state * s) +{ + if (!s) + s = (silence_state *) kmalloc(sizeof(silence_state), GFP_ATOMIC); + if (s) { + s->idx = 0; + s->state = 0; + } + return s; +} + +void +isdn_audio_calc_silence(modem_info * info, unsigned char *buf, int len, int fmt) +{ + silence_state *s = info->silence_state; + int i; + signed char c; + + if (!info->emu.vpar[1]) return; + + for (i = 0; i < len; i++) { + if (fmt) + c = isdn_audio_alaw_to_ulaw[*buf++]; + else + c = *buf++; + + if (c > 0) c -= 128; + c = abs(c); + + if (c > (info->emu.vpar[1] * 4)) { + s->idx = 0; + s->state = 1; + } else { + if (s->idx < 210000) s->idx++; + } + } +} + +void +isdn_audio_eval_silence(modem_info * info) +{ + silence_state *s = info->silence_state; + struct sk_buff *skb; + unsigned long flags; + int di; + int ch; + char what; + char *p; + + what = ' '; + + if (s->idx > (info->emu.vpar[2] * 800)) { + s->idx = 0; + if (!s->state) { /* silence from beginning of rec */ + what = 's'; + } else { + what = 'q'; + } + } + if ((what == 's') || (what == 'q')) { + printk(KERN_DEBUG "ttyI%d: %s\n", info->line, + (what=='s') ? "silence":"quiet"); + skb = dev_alloc_skb(2); + p = (char *) skb_put(skb, 2); + p[0] = 0x10; + p[1] = what; + if (skb_headroom(skb) < sizeof(isdn_audio_skb)) { + printk(KERN_WARNING + "isdn_audio: insufficient skb_headroom, dropping\n"); + kfree_skb(skb); + return; + } + ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; + ISDN_AUDIO_SKB_LOCK(skb) = 0; + save_flags(flags); + cli(); + di = info->isdn_driver; + ch = info->isdn_channel; + __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb); + dev->drv[di]->rcvcount[ch] += 2; + restore_flags(flags); + /* Schedule dequeuing */ + if ((dev->modempoll) && (info->rcvsched)) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); + wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); + } +} diff --git a/drivers/isdn/isdn_audio.h b/drivers/isdn/isdn_audio.h index 77091381..c44373da 100644 --- a/drivers/isdn/isdn_audio.h +++ b/drivers/isdn/isdn_audio.h @@ -19,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log$ + * Revision 1.5 1997/02/03 22:45:21 fritz + * Reformatted according CodingStyle + * * Revision 1.4 1996/06/06 14:43:32 fritz * Changed to support DTMF decoding on audio playback also. * @@ -48,6 +51,11 @@ typedef struct dtmf_state { int buf[DTMF_NPOINTS]; } dtmf_state; +typedef struct silence_state { + int state; + unsigned int idx; +} silence_state; + extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long); extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long); extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int); @@ -57,3 +65,6 @@ extern int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out); extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int); extern void isdn_audio_eval_dtmf(modem_info *); dtmf_state *isdn_audio_dtmf_init(dtmf_state *); +extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int); +extern void isdn_audio_eval_silence(modem_info *); +silence_state *isdn_audio_silence_init(silence_state *); diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index c67ead7a..c900b825 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -20,6 +20,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log$ + * Revision 1.57 1998/06/26 15:12:36 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * * Revision 1.56 1998/06/18 23:31:51 fritz * Replaced cli()/restore_flags() in isdn_tty_write() by locking. * Removed direct-senddown feature in isdn_tty_write because it will @@ -425,6 +430,8 @@ isdn_tty_readmodem(void) r = 0; #ifdef CONFIG_ISDN_AUDIO isdn_audio_eval_dtmf(info); + if (info->emu.vpar[1]) + isdn_audio_eval_silence(info); #endif if ((tty = info->tty)) { if (info->mcr & UART_MCR_RTS) { @@ -481,6 +488,8 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb) if (info->vonline) isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt); + if ((info->vonline & 1) && (info->emu.vpar[1])) + isdn_audio_calc_silence(info, skb->data, skb->len, ifmt); #endif if ((info->online < 2) #ifdef CONFIG_ISDN_AUDIO @@ -3462,6 +3471,11 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); PARSE_ERROR1; } + info->silence_state = isdn_audio_silence_init(info->silence_state); + if (!info->silence_state) { + printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n"); + PARSE_ERROR1; + } if (m->vpar[3] < 5) { info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]); if (!info->adpcmr) { @@ -3488,31 +3502,27 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) break; case '=': p[0]++; - switch (*p[0]) { - case '0': - case '1': - case '2': - case '3': - par1 = isdn_getnum(p); - if ((par1 < 0) || (par1 > 31)) - PARSE_ERROR1; - if (*p[0] != ',') - PARSE_ERROR1; - p[0]++; - par2 = isdn_getnum(p); - if ((par2 < 0) || (par2 > 255)) - PARSE_ERROR1; - m->vpar[1] = par1; - m->vpar[2] = par2; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n<0-31>,<0-255>", - info); - break; - default: + if ((*p[0]>='0') && (*p[0]<='9')) { + par1 = isdn_getnum(p); + if ((par1 < 0) || (par1 > 31)) PARSE_ERROR1; - } + if (*p[0] != ',') + PARSE_ERROR1; + p[0]++; + par2 = isdn_getnum(p); + if ((par2 < 0) || (par2 > 255)) + PARSE_ERROR1; + m->vpar[1] = par1; + m->vpar[2] = par2; + break; + } else + if (*p[0] == '?') { + p[0]++; + isdn_tty_at_cout("\r\n<0-31>,<0-255>", + info); + break; + } else + PARSE_ERROR1; break; default: PARSE_ERROR1; diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 1f7fdd47..b5febf74 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -21,6 +21,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log$ + * Revision 1.55 1998/06/26 15:13:17 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * * Revision 1.54 1998/06/18 23:32:01 fritz * Replaced cli()/restore_flags() in isdn_tty_write() by locking. * Removed direct-senddown feature in isdn_tty_write because it will @@ -716,6 +721,7 @@ typedef struct modem_info { void *adpcms; /* state for adpcm decompression */ void *adpcmr; /* state for adpcm compression */ void *dtmf_state; /* state for dtmf decoder */ + void *silence_state; /* state for silence detection */ #endif struct tty_struct *tty; /* Pointer to corresponding tty */ atemu emu; /* AT-emulator data */