1*74ba9207SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */ 2960366cfSKarsten Keil /* 3960366cfSKarsten Keil * SpanDSP - a series of DSP components for telephony 4960366cfSKarsten Keil * 5960366cfSKarsten Keil * ec_disable_detector.h - A detector which should eventually meet the 6960366cfSKarsten Keil * G.164/G.165 requirements for detecting the 7960366cfSKarsten Keil * 2100Hz echo cancellor disable tone. 8960366cfSKarsten Keil * 9960366cfSKarsten Keil * Written by Steve Underwood <steveu@coppice.org> 10960366cfSKarsten Keil * 11960366cfSKarsten Keil * Copyright (C) 2001 Steve Underwood 12960366cfSKarsten Keil * 13960366cfSKarsten Keil * All rights reserved. 14960366cfSKarsten Keil */ 15960366cfSKarsten Keil 16960366cfSKarsten Keil #include "dsp_biquad.h" 17960366cfSKarsten Keil 18960366cfSKarsten Keil struct ec_disable_detector_state { 19960366cfSKarsten Keil struct biquad2_state notch; 20960366cfSKarsten Keil int notch_level; 21960366cfSKarsten Keil int channel_level; 22960366cfSKarsten Keil int tone_present; 23960366cfSKarsten Keil int tone_cycle_duration; 24960366cfSKarsten Keil int good_cycles; 25960366cfSKarsten Keil int hit; 26960366cfSKarsten Keil }; 27960366cfSKarsten Keil 28960366cfSKarsten Keil 29960366cfSKarsten Keil #define FALSE 0 30960366cfSKarsten Keil #define TRUE (!FALSE) 31960366cfSKarsten Keil 32960366cfSKarsten Keil static inline void 33960366cfSKarsten Keil echo_can_disable_detector_init(struct ec_disable_detector_state *det) 34960366cfSKarsten Keil { 35960366cfSKarsten Keil /* Elliptic notch */ 36960366cfSKarsten Keil /* This is actually centred at 2095Hz, but gets the balance we want, due 37960366cfSKarsten Keil to the asymmetric walls of the notch */ 38960366cfSKarsten Keil biquad2_init(&det->notch, 39960366cfSKarsten Keil (int32_t)(-0.7600000 * 32768.0), 40960366cfSKarsten Keil (int32_t)(-0.1183852 * 32768.0), 41960366cfSKarsten Keil (int32_t)(-0.5104039 * 32768.0), 42960366cfSKarsten Keil (int32_t)(0.1567596 * 32768.0), 43960366cfSKarsten Keil (int32_t)(1.0000000 * 32768.0)); 44960366cfSKarsten Keil 45960366cfSKarsten Keil det->channel_level = 0; 46960366cfSKarsten Keil det->notch_level = 0; 47960366cfSKarsten Keil det->tone_present = FALSE; 48960366cfSKarsten Keil det->tone_cycle_duration = 0; 49960366cfSKarsten Keil det->good_cycles = 0; 50960366cfSKarsten Keil det->hit = 0; 51960366cfSKarsten Keil } 52960366cfSKarsten Keil /*- End of function --------------------------------------------------------*/ 53960366cfSKarsten Keil 54960366cfSKarsten Keil static inline int 55960366cfSKarsten Keil echo_can_disable_detector_update(struct ec_disable_detector_state *det, 56960366cfSKarsten Keil int16_t amp) 57960366cfSKarsten Keil { 58960366cfSKarsten Keil int16_t notched; 59960366cfSKarsten Keil 60960366cfSKarsten Keil notched = biquad2(&det->notch, amp); 61960366cfSKarsten Keil /* Estimate the overall energy in the channel, and the energy in 62960366cfSKarsten Keil the notch (i.e. overall channel energy - tone energy => noise). 63960366cfSKarsten Keil Use abs instead of multiply for speed (is it really faster?). 64960366cfSKarsten Keil Damp the overall energy a little more for a stable result. 65960366cfSKarsten Keil Damp the notch energy a little less, so we don't damp out the 66960366cfSKarsten Keil blip every time the phase reverses */ 67960366cfSKarsten Keil det->channel_level += ((abs(amp) - det->channel_level) >> 5); 68960366cfSKarsten Keil det->notch_level += ((abs(notched) - det->notch_level) >> 4); 69960366cfSKarsten Keil if (det->channel_level > 280) { 70960366cfSKarsten Keil /* There is adequate energy in the channel. 71960366cfSKarsten Keil Is it mostly at 2100Hz? */ 72960366cfSKarsten Keil if (det->notch_level * 6 < det->channel_level) { 73960366cfSKarsten Keil /* The notch says yes, so we have the tone. */ 74960366cfSKarsten Keil if (!det->tone_present) { 75960366cfSKarsten Keil /* Do we get a kick every 450+-25ms? */ 76960366cfSKarsten Keil if (det->tone_cycle_duration >= 425 * 8 77960366cfSKarsten Keil && det->tone_cycle_duration <= 475 * 8) { 78960366cfSKarsten Keil det->good_cycles++; 79960366cfSKarsten Keil if (det->good_cycles > 2) 80960366cfSKarsten Keil det->hit = TRUE; 81960366cfSKarsten Keil } 82960366cfSKarsten Keil det->tone_cycle_duration = 0; 83960366cfSKarsten Keil } 84960366cfSKarsten Keil det->tone_present = TRUE; 85960366cfSKarsten Keil } else 86960366cfSKarsten Keil det->tone_present = FALSE; 87960366cfSKarsten Keil det->tone_cycle_duration++; 88960366cfSKarsten Keil } else { 89960366cfSKarsten Keil det->tone_present = FALSE; 90960366cfSKarsten Keil det->tone_cycle_duration = 0; 91960366cfSKarsten Keil det->good_cycles = 0; 92960366cfSKarsten Keil } 93960366cfSKarsten Keil return det->hit; 94960366cfSKarsten Keil } 95960366cfSKarsten Keil /*- End of function --------------------------------------------------------*/ 96960366cfSKarsten Keil /*- End of file ------------------------------------------------------------*/ 97