1 /**
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <ImsMediaDefine.h>
18 #include <JitterNetworkAnalyser.h>
19 #include <ImsMediaTimer.h>
20 #include <ImsMediaTrace.h>
21 #include <numeric>
22 #include <cmath>
23 #include <algorithm>
24 #include <climits>
25
26 #define MAX_JITTER_LIST_SIZE (150)
27 #define PACKET_INTERVAL (20) // milliseconds
28 #define BUFFER_INCREASE_TH (200) // milliseconds
29 #define BUFFER_DECREASE_TH (2000) // milliseconds
30 #define MARGIN_WEIGHT (1.0f)
31 #define BUFFER_IN_DECREASE_SIZE (2)
32 #define ROUNDUP_MARGIN (10) // milliseconds
33
JitterNetworkAnalyser()34 JitterNetworkAnalyser::JitterNetworkAnalyser()
35 {
36 mMinJitterBufferSize = 0;
37 mMaxJitterBufferSize = 0;
38 mBufferIncThreshold = BUFFER_INCREASE_TH;
39 mBufferDecThreshold = BUFFER_DECREASE_TH;
40 mBufferStepSize = BUFFER_IN_DECREASE_SIZE;
41 mBufferWeight = MARGIN_WEIGHT;
42
43 IMLOGD4("[JitterNetworkAnalyser] incThreshold=%d, decThreshold=%d, stepSize=%d, "
44 "weight[%.3f]",
45 mBufferIncThreshold, mBufferDecThreshold, mBufferStepSize, mBufferWeight);
46 Reset();
47 }
48
~JitterNetworkAnalyser()49 JitterNetworkAnalyser::~JitterNetworkAnalyser() {}
50
Reset()51 void JitterNetworkAnalyser::Reset()
52 {
53 mNetworkStatus = NETWORK_STATUS_NORMAL;
54 mGoodStatusEnteringTime = 0;
55 mBadStatusChangedTime = 0;
56
57 {
58 std::lock_guard<std::mutex> guard(mMutex);
59 mListAccumDeltas.clear();
60 mPrevTimestamp = 0;
61 mPrevArrivalTime = 0;
62 mTimeLateArrivals = 0;
63 mPrevDelta = 0;
64 minJitterInBeginning = INT_MAX;
65 }
66 }
67
SetMinMaxJitterBufferSize(uint32_t nMinBufferSize,uint32_t nMaxBufferSize)68 void JitterNetworkAnalyser::SetMinMaxJitterBufferSize(
69 uint32_t nMinBufferSize, uint32_t nMaxBufferSize)
70 {
71 mMinJitterBufferSize = nMinBufferSize;
72 mMaxJitterBufferSize = nMaxBufferSize;
73 }
74
SetJitterOptions(uint32_t incThreshold,uint32_t decThreshold,uint32_t stepSize,double weight)75 void JitterNetworkAnalyser::SetJitterOptions(
76 uint32_t incThreshold, uint32_t decThreshold, uint32_t stepSize, double weight)
77 {
78 mBufferIncThreshold = incThreshold;
79 mBufferDecThreshold = decThreshold;
80 mBufferStepSize = stepSize;
81 mBufferWeight = weight;
82
83 IMLOGD4("[SetJitterOptions] incThreshold=%d, decThreshold=%d, stepSize=%d, weight[%.3f]",
84 mBufferIncThreshold, mBufferDecThreshold, mBufferStepSize, mBufferWeight);
85 }
86
87 template <typename Map>
getGreatestLess(Map const & m,typename Map::key_type const & k)88 typename Map::const_iterator getGreatestLess(Map const& m, typename Map::key_type const& k)
89 {
90 typename Map::const_iterator it = m.lower_bound(k);
91 if (it != m.begin())
92 {
93 return --it;
94 }
95 return m.end();
96 }
97
CalculateTransitTimeDifference(uint32_t timestamp,uint32_t arrivalTime)98 int32_t JitterNetworkAnalyser::CalculateTransitTimeDifference(
99 uint32_t timestamp, uint32_t arrivalTime)
100 {
101 std::lock_guard<std::mutex> guard(mMutex);
102
103 if (mPrevTimestamp == 0)
104 {
105 mPrevTimestamp = timestamp;
106 mPrevArrivalTime = arrivalTime;
107 minJitterInBeginning = INT_MAX;
108 return 0;
109 }
110
111 int32_t inputTimestampGap = timestamp - mPrevTimestamp;
112 int32_t inputTimeGap = arrivalTime - mPrevArrivalTime;
113 int32_t delta = inputTimeGap - inputTimestampGap;
114
115 mPrevTimestamp = timestamp;
116 mPrevArrivalTime = arrivalTime;
117
118 mPrevDelta += delta;
119 mListAccumDeltas.push_back(
120 minJitterInBeginning == INT_MAX ? mPrevDelta : mPrevDelta - minJitterInBeginning);
121
122 if (mListAccumDeltas.size() > MAX_JITTER_LIST_SIZE)
123 {
124 mListAccumDeltas.pop_front();
125 }
126 else
127 {
128 // for normalization
129 if (minJitterInBeginning > mPrevDelta)
130 {
131 minJitterInBeginning = mPrevDelta;
132 }
133 }
134
135 return delta;
136 }
137
SetLateArrivals(uint32_t time)138 void JitterNetworkAnalyser::SetLateArrivals(uint32_t time)
139 {
140 mTimeLateArrivals = time;
141 }
142
CalculateDeviation(double * pMean)143 double JitterNetworkAnalyser::CalculateDeviation(double* pMean)
144 {
145 std::lock_guard<std::mutex> guard(mMutex);
146
147 if (mListAccumDeltas.empty())
148 {
149 *pMean = 0;
150 return 0.0f;
151 }
152
153 double mean = std::accumulate(mListAccumDeltas.begin(), mListAccumDeltas.end(), 0.0f) /
154 mListAccumDeltas.size();
155
156 *pMean = mean;
157
158 double dev = sqrt(std::accumulate(mListAccumDeltas.begin(), mListAccumDeltas.end(), 0.0f,
159 [mean](int x, int y)
160 {
161 return x + std::pow(y - mean, 2);
162 }) /
163 mListAccumDeltas.size());
164
165 return dev;
166 }
167
GetMaxJitterValue()168 int32_t JitterNetworkAnalyser::GetMaxJitterValue()
169 {
170 std::lock_guard<std::mutex> guard(mMutex);
171
172 if (mListAccumDeltas.empty())
173 {
174 return 0;
175 }
176
177 return *std::max_element(mListAccumDeltas.begin(), mListAccumDeltas.end());
178 }
179
GetNextJitterBufferSize(uint32_t nCurrJitterBufferSize,uint32_t currentTime)180 uint32_t JitterNetworkAnalyser::GetNextJitterBufferSize(
181 uint32_t nCurrJitterBufferSize, uint32_t currentTime)
182 {
183 uint32_t nextJitterBuffer = nCurrJitterBufferSize;
184 NETWORK_STATUS networkStatus;
185
186 double dev, mean;
187 double calcJitterSize = 0;
188 int32_t maxJitter = GetMaxJitterValue();
189 dev = CalculateDeviation(&mean);
190 calcJitterSize = (double)maxJitter * mBufferWeight + ROUNDUP_MARGIN;
191 uint32_t bufferSize = calcJitterSize / PACKET_INTERVAL;
192
193 if (bufferSize > nCurrJitterBufferSize)
194 {
195 networkStatus = NETWORK_STATUS_BAD;
196 }
197 else if (bufferSize < nCurrJitterBufferSize - 1)
198 {
199 networkStatus = NETWORK_STATUS_GOOD;
200 }
201 else
202 {
203 networkStatus = NETWORK_STATUS_NORMAL;
204 }
205
206 IMLOGD_PACKET6(IM_PACKET_LOG_JITTER,
207 "[GetNextJitterBufferSize] size=%4.2f, mean=%4.2f, dev=%4.2f, max=%d, curr=%d, "
208 "status=%d",
209 calcJitterSize, mean, dev, maxJitter, nCurrJitterBufferSize, networkStatus);
210
211 switch (networkStatus)
212 {
213 case NETWORK_STATUS_BAD:
214 {
215 nextJitterBuffer = bufferSize;
216
217 if (nextJitterBuffer > mMaxJitterBufferSize)
218 {
219 nextJitterBuffer = mMaxJitterBufferSize;
220 }
221 else if (nextJitterBuffer < mMinJitterBufferSize)
222 {
223 nextJitterBuffer = mMinJitterBufferSize;
224 }
225
226 IMLOGD_PACKET2(IM_PACKET_LOG_JITTER,
227 "[GetNextJitterBufferSize] increase curr=%d, next=%d", nCurrJitterBufferSize,
228 nextJitterBuffer);
229 break;
230 }
231 case NETWORK_STATUS_GOOD:
232 {
233 if (mNetworkStatus != NETWORK_STATUS_GOOD)
234 {
235 mGoodStatusEnteringTime = currentTime;
236 }
237 else
238 {
239 uint32_t nTimeDiff = currentTime - mGoodStatusEnteringTime;
240
241 if (nTimeDiff >= mBufferDecThreshold &&
242 (mTimeLateArrivals == 0 ||
243 currentTime - mTimeLateArrivals > mBufferDecThreshold))
244 {
245 uint32_t decreaseStep = nCurrJitterBufferSize - bufferSize;
246
247 decreaseStep > mBufferStepSize
248 ? nextJitterBuffer = nCurrJitterBufferSize - mBufferStepSize
249 : nextJitterBuffer = nCurrJitterBufferSize - decreaseStep;
250
251 if (nextJitterBuffer < mMinJitterBufferSize)
252 {
253 nextJitterBuffer = mMinJitterBufferSize;
254 }
255
256 IMLOGD_PACKET2(IM_PACKET_LOG_JITTER,
257 "[GetNextJitterBufferSize] decrease curr=%d, next=%d",
258 nCurrJitterBufferSize, nextJitterBuffer);
259 networkStatus = NETWORK_STATUS_NORMAL;
260 }
261 }
262
263 break;
264 }
265 default:
266 nextJitterBuffer = nCurrJitterBufferSize;
267 break;
268 }
269
270 mNetworkStatus = networkStatus;
271 return nextJitterBuffer;
272 }
273