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