1 /*
2  * silencedetect.cxx
3  *
4  * Open Phone Abstraction Library (OPAL)
5  * Formally known as the Open H323 project.
6  *
7  * Copyright (c) 2001 Post Increment
8  *
9  * The contents of this file are subject to the Mozilla Public License
10  * Version 1.0 (the "License"); you may not use this file except in
11  * compliance with the License. You may obtain a copy of the License at
12  * http://www.mozilla.org/MPL/
13  *
14  * Software distributed under the License is distributed on an "AS IS"
15  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
16  * the License for the specific language governing rights and limitations
17  * under the License.
18  *
19  * The Original Code is Open Phone Abstraction Library.
20  *
21  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
22  *
23  * Contributor(s): ______________________________________.
24  *
25  * $Revision: 23735 $
26  * $Author: rjongbloed $
27  * $Date: 2009-10-30 21:20:26 -0500 (Fri, 30 Oct 2009) $
28  */
29 
30 #include <ptlib.h>
31 
32 #ifdef __GNUC__
33 #pragma implementation "silencedetect.h"
34 #endif
35 #include <opal/buildopts.h>
36 
37 #include <codec/silencedetect.h>
38 #include <opal/patch.h>
39 
40 #define new PNEW
41 
42 
43 extern "C" {
44   unsigned char linear2ulaw(int pcm_val);
45   int ulaw2linear(unsigned char u_val);
46 };
47 
48 
operator <<(ostream & strm,OpalSilenceDetector::Mode mode)49 ostream & operator<<(ostream & strm, OpalSilenceDetector::Mode mode)
50 {
51   static const char * const names[OpalSilenceDetector::NumModes] = {
52       "NoSilenceDetection",
53       "FixedSilenceDetection",
54       "AdaptiveSilenceDetection"
55   };
56 
57   if (mode >= 0 && mode < OpalSilenceDetector::NumModes && names[mode] != NULL)
58     strm << names[mode];
59   else
60     strm << "OpalSilenceDetector::Modes<" << mode << '>';
61   return strm;
62 }
63 
64 
65 ///////////////////////////////////////////////////////////////////////////////
66 
OpalSilenceDetector(const Params & theParam)67 OpalSilenceDetector::OpalSilenceDetector(const Params & theParam)
68 #ifdef _MSC_VER
69 #pragma warning(disable:4355)
70 #endif
71   : receiveHandler(PCREATE_NOTIFIER(ReceivedPacket)),
72 #ifdef _MSC_VER
73 #pragma warning(default:4355)
74 #endif
75   clockRate (8000)
76 {
77   // Initialise the adaptive threshold variables.
78   SetParameters(theParam);
79 
80   PTRACE(4, "Silence\tHandler created");
81 }
82 
83 
AdaptiveReset()84 void OpalSilenceDetector::AdaptiveReset()
85 {
86   // Initialise threshold level
87   levelThreshold = 0;
88 
89   // Initialise the adaptive threshold variables.
90   signalMinimum = UINT_MAX;
91   silenceMaximum = 0;
92   signalReceivedTime = 0;
93   silenceReceivedTime = 0;
94 
95   // Restart in silent mode
96   inTalkBurst = false;
97   lastTimestamp = 0;
98   receivedTime = 0;
99 }
100 
101 
SetParameters(const Params & newParam,const int rate)102 void OpalSilenceDetector::SetParameters(const Params & newParam, const int rate /*= 0*/)
103 {
104   PWaitAndSignal mutex(inUse);
105   if (rate)
106     clockRate = rate;
107   mode = newParam.m_mode;
108   signalDeadband = newParam.m_signalDeadband * clockRate / 1000;
109   silenceDeadband = newParam.m_silenceDeadband * clockRate / 1000;
110   adaptivePeriod = newParam.m_adaptivePeriod * clockRate / 1000;
111   if (mode == FixedSilenceDetection)
112     levelThreshold = newParam.m_threshold;// note: this value compared to uLaw encoded signal level
113   else
114     AdaptiveReset();
115 
116   PTRACE(4, "Silence\tParameters set: "
117             "mode=" << mode << ", "
118             "threshold=" << levelThreshold << ", "
119             "silencedb=" << silenceDeadband << " samples, "
120             "signaldb=" << signalDeadband << " samples, "
121             "period=" << adaptivePeriod << " samples");
122 }
123 
124 
SetClockRate(const int rate)125 void OpalSilenceDetector::SetClockRate(const int rate)
126 {
127   PWaitAndSignal mutex(inUse);
128   signalDeadband = signalDeadband * 1000 / clockRate * rate / 1000;
129   silenceDeadband = silenceDeadband * 1000 / clockRate * rate / 1000;
130   adaptivePeriod = adaptivePeriod * 1000 / clockRate * rate / 1000;
131   clockRate = rate;
132   if (mode == AdaptiveSilenceDetection)
133     AdaptiveReset();
134 }
135 
136 
GetStatus(PBoolean * isInTalkBurst,unsigned * currentThreshold) const137 OpalSilenceDetector::Mode OpalSilenceDetector::GetStatus(PBoolean * isInTalkBurst,
138                                                        unsigned * currentThreshold) const
139 {
140   if (isInTalkBurst != NULL)
141     *isInTalkBurst = inTalkBurst;
142 
143   if (currentThreshold != NULL)
144     *currentThreshold = ulaw2linear((BYTE)(levelThreshold ^ 0xff));
145 
146   return mode;
147 }
148 
149 
ReceivedPacket(RTP_DataFrame & frame,INT)150 void OpalSilenceDetector::ReceivedPacket(RTP_DataFrame & frame, INT)
151 {
152   // Already silent
153   if (frame.GetPayloadSize() == 0)
154     return;
155 
156   PWaitAndSignal mutex(inUse);
157 
158   // Can never have silence if NoSilenceDetection
159   if (mode == NoSilenceDetection)
160     return;
161 
162   unsigned thisTimestamp = frame.GetTimestamp();
163   if (lastTimestamp == 0) {
164     lastTimestamp = thisTimestamp;
165     return;
166   }
167 
168   unsigned timeSinceLastFrame = thisTimestamp - lastTimestamp;
169   lastTimestamp = thisTimestamp;
170 
171   // Average is absolute value up to 32767
172   unsigned level = GetAverageSignalLevel(frame.GetPayloadPtr(), frame.GetPayloadSize());
173 
174   // Can never have average signal level that high, this indicates that the
175   // hardware cannot do silence detection.
176   if (level == UINT_MAX)
177     return;
178 
179   // Convert to a logarithmic scale - use uLaw which is complemented
180   level = linear2ulaw(level) ^ 0xff;
181 
182   // Now if signal level above threshold we are "talking"
183   PBoolean haveSignal = level > levelThreshold;
184 
185   // If no change ie still talking or still silent, reset frame counter
186   if (inTalkBurst == haveSignal)
187     receivedTime = 0;
188   else {
189     receivedTime += timeSinceLastFrame;
190     // If have had enough consecutive frames talking/silent, swap modes.
191     if (receivedTime >= (inTalkBurst ? silenceDeadband : signalDeadband)) {
192       inTalkBurst = !inTalkBurst;
193       PTRACE(4, "Silence\tDetector transition: "
194              << (inTalkBurst ? "Talk" : "Silent")
195              << " level=" << level << " threshold=" << levelThreshold);
196 
197       // If we had talk/silence transition restart adaptive threshold measurements
198       signalMinimum = UINT_MAX;
199       silenceMaximum = 0;
200       signalReceivedTime = 0;
201       silenceReceivedTime = 0;
202 
203       // If we just have moved to sending a talk burst, set the RTP marker
204       if (inTalkBurst)
205         frame.SetMarker(true);
206     }
207   }
208 
209   if (mode == FixedSilenceDetection) {
210     if (!inTalkBurst)
211       frame.SetPayloadSize(0); // Not in talk burst so silence the frame
212     return;
213   }
214 
215   // Adaptive silence detection
216   if (levelThreshold == 0) {
217     if (level > 1) {
218       // Bootstrap condition, use first frame level as silence level
219       levelThreshold = level/2;
220       PTRACE(4, "Silence\tThreshold initialised to: " << levelThreshold);
221     }
222     // inTalkBurst always PFalse here, so return silent
223     frame.SetPayloadSize(0);
224     return;
225   }
226 
227   // Count the number of silent and signal frames and calculate min/max
228   if (haveSignal) {
229     if (level < signalMinimum)
230       signalMinimum = level;
231     signalReceivedTime=signalReceivedTime+timeSinceLastFrame;
232   }
233   else {
234     if (level > silenceMaximum)
235       silenceMaximum = level;
236     silenceReceivedTime=silenceReceivedTime+timeSinceLastFrame;
237   }
238 
239   // See if we have had enough frames to look at proportions of silence/signal
240   if ((signalReceivedTime + silenceReceivedTime) > adaptivePeriod) {
241 
242     /* Now we have had a period of time to look at some average values we can
243        make some adjustments to the threshold. There are four cases:
244      */
245     if (signalReceivedTime >= adaptivePeriod) {
246       /* If every frame was noisy, move threshold up. Don't want to move too
247          fast so only go a quarter of the way to minimum signal value over the
248          period. This avoids oscillations, and time will continue to make the
249          level go up if there really is a lot of background noise.
250        */
251       int delta = (signalMinimum - levelThreshold)/4;
252       if (delta != 0) {
253         levelThreshold += delta;
254         PTRACE(4, "Silence\tThreshold increased to: " << levelThreshold);
255       }
256     }
257     else if (silenceReceivedTime >= adaptivePeriod) {
258       /* If every frame was silent, move threshold down. Again do not want to
259          move too quickly, but we do want it to move faster down than up, so
260          move to halfway to maximum value of the quiet period. As a rule the
261          lower the threshold the better as it would improve response time to
262          the start of a talk burst.
263        */
264       unsigned newThreshold = (levelThreshold + silenceMaximum)/2 + 1;
265       if (levelThreshold != newThreshold) {
266         levelThreshold = newThreshold;
267         PTRACE(4, "Silence\tThreshold decreased to: " << levelThreshold);
268       }
269     }
270     else if (signalReceivedTime > silenceReceivedTime) {
271       /* We haven't got a definitive silent or signal period, but if we are
272          constantly hovering at the threshold and have more signal than
273          silence we should creep up a bit.
274        */
275       levelThreshold++;
276       PTRACE(4, "Silence\tThreshold incremented to: " << levelThreshold
277              << " signal=" << signalReceivedTime << ' ' << signalMinimum
278              << " silence=" << silenceReceivedTime << ' ' << silenceMaximum);
279     }
280 
281     signalMinimum = UINT_MAX;
282     silenceMaximum = 0;
283     signalReceivedTime = 0;
284     silenceReceivedTime = 0;
285   }
286 
287   if (!inTalkBurst)
288     frame.SetPayloadSize(0); // Not in talk burst so silence the frame
289 }
290 
291 
292 /////////////////////////////////////////////////////////////////////////////
293 
GetAverageSignalLevel(const BYTE * buffer,PINDEX size)294 unsigned OpalPCM16SilenceDetector::GetAverageSignalLevel(const BYTE * buffer, PINDEX size)
295 {
296   // Calculate the average signal level of this frame
297   int sum = 0;
298   PINDEX samples = size/2;
299   const short * pcm = (const short *)buffer;
300   const short * end = pcm + samples;
301   while (pcm != end) {
302     if (*pcm < 0)
303       sum -= *pcm++;
304     else
305       sum += *pcm++;
306   }
307 
308   return sum/samples;
309 }
310 
311 
312 /////////////////////////////////////////////////////////////////////////////
313