Reviewed and adjusted PTRACE log levels
[opal.git] / src / codec / silencedetect.cxx
blob4e4b724e4a8fb119ea4d51f3faa8f0d7ce7fbd55
1 /*
2 * silencedetect.cxx
4 * Open Phone Abstraction Library (OPAL)
5 * Formally known as the Open H323 project.
7 * Copyright (c) 2001 Post Increment
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/
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.
19 * The Original Code is Open Phone Abstraction Library.
21 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23 * Contributor(s): ______________________________________.
25 * $Log$
26 * Revision 1.5 2007/04/04 02:12:00 rjongbloed
27 * Reviewed and adjusted PTRACE log levels
28 * Now follows 1=error,2=warn,3=info,4+=debug
30 * Revision 1.4 2005/07/09 06:52:39 rjongbloed
31 * Added print (operator<<) of silence detect mode enum.
33 * Revision 1.3 2005/03/06 15:00:26 dsandras
34 * Fixed silence detection, we are now working with time frames, not the number of frames.
36 * Revision 1.2 2004/05/24 13:39:26 rjongbloed
37 * Fixed setting marker bit when silence suppression transitions from
38 * silence to signal, thanks Ted Szoczei
39 * Added a separate structure for the silence suppression paramters to make
40 * it easier to set from global defaults in the manager class.
42 * Revision 1.1 2004/05/17 13:24:26 rjongbloed
43 * Added silence suppression.
47 #include <ptlib.h>
49 #ifdef __GNUC__
50 #pragma implementation "silencedetect.h"
51 #endif
53 #include <codec/silencedetect.h>
54 #include <opal/patch.h>
56 #define new PNEW
59 extern "C" {
60 unsigned char linear2ulaw(int pcm_val);
61 int ulaw2linear(unsigned char u_val);
65 ostream & operator<<(ostream & strm, OpalSilenceDetector::Mode mode)
67 static const char * const names[OpalSilenceDetector::NumModes] = {
68 "NoSilenceDetection",
69 "FixedSilenceDetection",
70 "AdaptiveSilenceDetection"
73 if (mode >= 0 && mode < OpalSilenceDetector::NumModes && names[mode] != NULL)
74 strm << names[mode];
75 else
76 strm << "OpalSilenceDetector::Modes<" << mode << '>';
77 return strm;
81 ///////////////////////////////////////////////////////////////////////////////
83 OpalSilenceDetector::OpalSilenceDetector()
84 #ifdef _MSC_VER
85 #pragma warning(disable:4355)
86 #endif
87 : receiveHandler(PCREATE_NOTIFIER(ReceivedPacket))
88 #ifdef _MSC_VER
89 #pragma warning(default:4355)
90 #endif
92 // Start off in silent mode
93 inTalkBurst = FALSE;
95 // Initialise the adaptive threshold variables.
96 SetParameters(param);
98 PTRACE(4, "Silence\tHandler created");
102 void OpalSilenceDetector::SetParameters(const Params & newParam)
104 param = newParam;
106 if (param.m_mode != AdaptiveSilenceDetection) {
107 levelThreshold = param.m_threshold;
108 return;
111 // Initials threshold levels
112 levelThreshold = 0;
114 // Initialise the adaptive threshold variables.
115 signalMinimum = UINT_MAX;
116 silenceMaximum = 0;
117 signalReceivedTime = 0;
118 silenceReceivedTime = 0;
120 // Restart in silent mode
121 inTalkBurst = FALSE;
122 lastTimestamp = 0;
123 receivedTime = 0;
127 OpalSilenceDetector::Mode OpalSilenceDetector::GetStatus(BOOL * isInTalkBurst,
128 unsigned * currentThreshold) const
130 if (isInTalkBurst != NULL)
131 *isInTalkBurst = inTalkBurst;
133 if (currentThreshold != NULL)
134 *currentThreshold = ulaw2linear((BYTE)(levelThreshold ^ 0xff));
136 return param.m_mode;
140 void OpalSilenceDetector::ReceivedPacket(RTP_DataFrame & frame, INT)
142 // Already silent
143 if (frame.GetPayloadSize() == 0)
144 return;
146 // Can never have silence if NoSilenceDetection
147 if (param.m_mode == NoSilenceDetection)
148 return;
150 unsigned thisTimestamp = frame.GetTimestamp();
151 if (lastTimestamp == 0) {
152 lastTimestamp = thisTimestamp;
153 return;
156 unsigned timeSinceLastFrame = thisTimestamp - lastTimestamp;
157 lastTimestamp = thisTimestamp;
159 // Can never have average signal level that high, this indicates that the
160 // hardware cannot do silence detection.
161 unsigned level = GetAverageSignalLevel(frame.GetPayloadPtr(), frame.GetPayloadSize());
162 if (level == UINT_MAX)
163 return;
165 // Convert to a logarithmic scale - use uLaw which is complemented
166 level = linear2ulaw(level) ^ 0xff;
168 // Now if signal level above threshold we are "talking"
169 BOOL haveSignal = level > levelThreshold;
171 // If no change ie still talking or still silent, resent frame counter
172 if (inTalkBurst == haveSignal)
173 receivedTime = 0;
174 else {
175 receivedTime += timeSinceLastFrame;
176 // If have had enough consecutive frames talking/silent, swap modes.
177 if (receivedTime >= (inTalkBurst ? param.m_silenceDeadband : param.m_signalDeadband)) {
178 inTalkBurst = !inTalkBurst;
179 PTRACE(4, "Silence\tDetector transition: "
180 << (inTalkBurst ? "Talk" : "Silent")
181 << " level=" << level << " threshold=" << levelThreshold);
183 // If we had talk/silence transition restart adaptive threshold measurements
184 signalMinimum = UINT_MAX;
185 silenceMaximum = 0;
186 signalReceivedTime = 0;
187 silenceReceivedTime = 0;
189 // If we just have moved to sending a talk burst, set the RTP marker
190 if (inTalkBurst)
191 frame.SetMarker(TRUE);
195 if (param.m_mode == FixedSilenceDetection) {
196 if (!inTalkBurst)
197 frame.SetPayloadSize(0); // Not in talk burst so silence the frame
198 return;
201 if (levelThreshold == 0) {
202 if (level > 1) {
203 // Bootstrap condition, use first frame level as silence level
204 levelThreshold = level/2;
205 PTRACE(4, "Silence\tThreshold initialised to: " << levelThreshold);
207 // inTalkBurst always FALSE here, so return silent
208 frame.SetPayloadSize(0);
209 return;
212 // Count the number of silent and signal frames and calculate min/max
213 if (haveSignal) {
214 if (level < signalMinimum)
215 signalMinimum = level;
216 signalReceivedTime=signalReceivedTime+timeSinceLastFrame;
218 else {
219 if (level > silenceMaximum)
220 silenceMaximum = level;
221 silenceReceivedTime=silenceReceivedTime+timeSinceLastFrame;
224 // See if we have had enough frames to look at proportions of silence/signal
225 if ((signalReceivedTime + silenceReceivedTime) > param.m_adaptivePeriod) {
227 /* Now we have had a period of time to look at some average values we can
228 make some adjustments to the threshold. There are four cases:
230 if (signalReceivedTime >= param.m_adaptivePeriod) {
231 /* If every frame was noisy, move threshold up. Don't want to move too
232 fast so only go a quarter of the way to minimum signal value over the
233 period. This avoids oscillations, and time will continue to make the
234 level go up if there really is a lot of background noise.
236 int delta = (signalMinimum - levelThreshold)/4;
237 if (delta != 0) {
238 levelThreshold += delta;
239 PTRACE(4, "Silence\tThreshold increased to: " << levelThreshold);
242 else if (silenceReceivedTime >= param.m_adaptivePeriod) {
243 /* If every frame was silent, move threshold down. Again do not want to
244 move too quickly, but we do want it to move faster down than up, so
245 move to halfway to maximum value of the quiet period. As a rule the
246 lower the threshold the better as it would improve response time to
247 the start of a talk burst.
249 unsigned newThreshold = (levelThreshold + silenceMaximum)/2 + 1;
250 if (levelThreshold != newThreshold) {
251 levelThreshold = newThreshold;
252 PTRACE(4, "Silence\tThreshold decreased to: " << levelThreshold);
255 else if (signalReceivedTime > silenceReceivedTime) {
256 /* We haven't got a definitive silent or signal period, but if we are
257 constantly hovering at the threshold and have more signal than
258 silence we should creep up a bit.
260 levelThreshold++;
261 PTRACE(4, "Silence\tThreshold incremented to: " << levelThreshold
262 << " signal=" << signalReceivedTime << ' ' << signalMinimum
263 << " silence=" << silenceReceivedTime << ' ' << silenceMaximum);
266 signalMinimum = UINT_MAX;
267 silenceMaximum = 0;
268 signalReceivedTime = 0;
269 silenceReceivedTime = 0;
272 if (!inTalkBurst)
273 frame.SetPayloadSize(0); // Not in talk burst so silence the frame
277 /////////////////////////////////////////////////////////////////////////////
279 unsigned OpalPCM16SilenceDetector::GetAverageSignalLevel(const BYTE * buffer, PINDEX size)
281 // Calculate the average signal level of this frame
282 int sum = 0;
283 PINDEX samples = size/2;
284 const short * pcm = (const short *)buffer;
285 const short * end = pcm + samples;
286 while (pcm != end) {
287 if (*pcm < 0)
288 sum -= *pcm++;
289 else
290 sum += *pcm++;
293 return sum/samples;
297 /////////////////////////////////////////////////////////////////////////////