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 #ifndef MEDIA_QUALITY_ANALYZER_H_INCLUDED
18 #define MEDIA_QUALITY_ANALYZER_H_INCLUDED
19 
20 #include <CallQuality.h>
21 #include <ImsMediaDefine.h>
22 #include <IImsMediaThread.h>
23 #include <ImsMediaCondition.h>
24 #include <RtcpXrEncoder.h>
25 #include <BaseSessionCallback.h>
26 #include <AudioConfig.h>
27 #include <MediaQualityThreshold.h>
28 #include <MediaQualityStatus.h>
29 #include <list>
30 #include <vector>
31 #include <mutex>
32 #include <algorithm>
33 
34 class HysteresisTimeChecker
35 {
36 public:
37     HysteresisTimeChecker(int32_t time = 0)
38     {
39         hysteresisTime = time;
40         countHysteresisTime = hysteresisTime;
41         notifiedDirection = 1;
42         firstNotified = false;
43         previousValue = 0;
44     }
45 
initialize(int32_t time)46     void initialize(int32_t time)
47     {
48         hysteresisTime = time;
49         countHysteresisTime = hysteresisTime;
50         notifiedDirection = 1;
51         firstNotified = false;
52         previousValue = 0;
53     }
54 
~HysteresisTimeChecker()55     ~HysteresisTimeChecker() {}
56 
checkNotifiable(std::vector<int32_t> thresholds,int32_t currentValue)57     bool checkNotifiable(std::vector<int32_t> thresholds, int32_t currentValue)
58     {
59         if (thresholds.empty())
60         {
61             return false;
62         }
63 
64         bool notifiable = false;
65 
66         // cross the threshold case
67         auto iterCrossed = find_if(thresholds.begin(), thresholds.end(),
68                 [=, *this](int32_t thres)
69                 {
70                     return ((currentValue >= thres && previousValue < thres) ||
71                             (currentValue < thres && previousValue >= thres));
72                 });
73 
74         if (iterCrossed != thresholds.end())
75         {
76             uint32_t currentDirection = (currentValue - previousValue) > 0 ? 1 : 0;
77 
78             if (countHysteresisTime >= hysteresisTime || currentDirection == notifiedDirection)
79             {
80                 if (!firstNotified)
81                 {
82                     firstNotified = true;
83                 }
84 
85                 previousValue = currentValue;
86                 countHysteresisTime = 0;
87                 notifiedDirection = currentDirection;
88                 notifiable = true;
89             }
90 
91             countHysteresisTime++;
92         }
93         else
94         {
95             if (firstNotified)
96             {
97                 countHysteresisTime = 1;
98             }
99         }
100 
101         return notifiable;
102     }
103 
104     int32_t hysteresisTime;
105     int32_t countHysteresisTime;
106     int32_t previousValue;
107     uint32_t notifiedDirection;
108     bool firstNotified;
109 };
110 
111 class MediaQualityAnalyzer : public IImsMediaThread
112 {
113 public:
114     MediaQualityAnalyzer();
115     virtual ~MediaQualityAnalyzer();
116 
117     /**
118      * @brief Set the session callback to send the event
119      */
120     void setCallback(BaseSessionCallback* callback);
121 
122     /**
123      * @brief Sets the audio codec type
124      * @param config The AudioConfig to set
125      */
126     void setConfig(AudioConfig* config);
127 
128     /**
129      * @brief Set the MediaQualityThreshold
130      */
131     void setMediaQualityThreshold(const MediaQualityThreshold& threshold);
132 
133     /**
134      * @brief Sets the interval of the RTP reception statistics notification params for checking the
135      *        current status of the rtp stream. It will trigger the notifyRtpReceptionStats() with
136      *        the RtpReceptionStats.
137      *
138      * @param intervalMs The interval of the time in milliseconds of the rtp reception notification
139      */
140     void setNotifyRtpReceptionStatsInterval(const int32_t intervalMs);
141 
142     /**
143      * @brief Check the audio config has different codec values
144      *
145      * @param config The AudioConfig to compare
146      */
147     bool isSameConfig(AudioConfig* config);
148 
149     /**
150      * @brief Start for calculating statistics from collected datas
151      */
152     void start();
153 
154     /**
155      * @brief Stop calculating the statistics from collected datas and send a report
156      */
157     void stop();
158 
159     /**
160      * @brief Collect information of sending or receiving the rtp or the rtcp packet datas.
161      *
162      * @param streamType The stream type. Tx, Rx, Rtcp.
163      * @param param The structure set of the rtp/rtcp payload.
164      */
165     void collectInfo(const int32_t streamType, uint64_t param);
166 
167     /**
168      * @brief Collect optional information of sending or receiving the rtp or rtcp packet datas.
169      *
170      * @param optionType The optional type to collect. The TTL or the Round Trip delay.
171      * @param seq The sequence number of the packet to collect.
172      * @param value The optional value to collect.
173      */
174     void collectOptionalInfo(const int32_t optionType, const int32_t seq, const int32_t value);
175 
176     /**
177      * @brief Collects Rtp status determined from the jitter buffer.
178      *
179      * @param seq The packet sequence number to collect.
180      * @param status The status of the packet. Check in @link{kRtpPacketStatus}
181      * @param time The time marked when the frame was played in milliseconds unit
182      */
183     void collectRxRtpStatus(const int32_t seq, const kRtpPacketStatus status, const uint32_t time);
184 
185     /**
186      * @brief Collects jitter buffer size.
187      *
188      * @param currSize The current size of the jitter buffer.
189      * @param maxSize The maximum jitter buffer size.
190      */
191     void collectJitterBufferSize(const int32_t currSize, const int32_t maxSize);
192 
193     /**
194      * @brief generate  Rtcp-Xr report blocks with given report block enabled in bitmask type
195      *
196      * @param nReportBlocks The bitmask of report block to creates
197      * @param data The byte array of total report blocks
198      * @param size The size of total report blocks together
199      * @return true The report block is not zero and data is valid
200      * @return false The report block is zero or got error during create the report block
201      */
202     bool getRtcpXrReportBlock(const uint32_t nReportBlocks, uint8_t* data, uint32_t& size);
203 
204     /**
205      * @brief Get the CallQuality member instance
206      */
207     CallQuality getCallQuality();
208 
209     /**
210      * @brief Get number of rx packets in the list
211      */
212     uint32_t getRxPacketSize();
213 
214     /**
215      * @brief Get number of tx packets in the list
216      */
217     uint32_t getTxPacketSize();
218 
219     /**
220      * @brief Get number of lost packets in the list
221      */
222     uint32_t getLostPacketSize();
223 
224     /**
225      * @brief Set the event handler time factor. This method is to adjust the event timing intervals
226      * only for the testing purpose to reduce the testing time. The normal case, the default time
227      * interval will be used.
228      *
229      * For example: if 100 is passed in, then the event processing period will be reduced from
230      * 20ms to 200us and the call quality processing period will be reduced from 1 second to 10ms.
231      *
232      * @param timeFactor Time intervals will be divided by this value.  The maximum value is 1000.
233      */
234     void setEventTimeFactor(const uint32_t timeFactor);
235 
236     /**
237      * @brief Send message event to event handler
238      *
239      * @param event The event type
240      * @param paramA The 1st parameter
241      * @param paramB The 2nd parameter
242      */
243     void SendEvent(uint32_t event, uint64_t paramA, uint64_t paramB = 0);
244 
245 protected:
246     /**
247      * @brief Process the data stacked in the list
248      *
249      * @param timeCount The count increased every second
250      */
251     void processData(const int32_t timeCount);
252     void processMediaQuality();
253     void processRtpReceptionStats(const int32_t timeCount);
254     void notifyCallQuality();
255     void notifyMediaQualityStatus();
256     void AddEvent(uint32_t event, uint64_t paramA, uint64_t paramB);
257     void processEvent(uint32_t event, uint64_t paramA, uint64_t paramB);
258     virtual void* run();
259     void reset();
260     void clearPacketList(std::list<RtpPacket*>& list, const int32_t seq);
261     void clearLostPacketList(const int32_t seq);
262     uint32_t getCallQuality(double lossRate);
263     int32_t convertAudioCodecType(const int32_t codec, const int32_t bandwidth);
264 
265     BaseSessionCallback* mCallback;
266     std::unique_ptr<RtcpXrEncoder> mRtcpXrEncoder;
267     /** The list of the packets received ordered by arrival time */
268     std::list<RtpPacket*> mListRxPacket;
269     /** The list of the lost packets object */
270     std::list<LostPacket*> mListLostPacket;
271     /** The list of the packets sent */
272     std::list<RtpPacket*> mListTxPacket;
273     /** The time of call started in milliseconds unit*/
274     int32_t mTimeStarted;
275     /** The ssrc of the receiving Rtp stream to identify */
276     int32_t mSSRC;
277     /** The codec type of the audio session retrieved from the AudioConfig.h */
278     int32_t mCodecType;
279     /** The codec attribute of the audio session, it could be bandwidth in evs codec */
280     int32_t mCodecAttribute;
281     /** Whether RTP is activated for the receiver or not */
282     bool mIsRxRtpEnabled;
283     /** Whether RTCP is activated for both sender and receiver */
284     bool mIsRtcpEnabled;
285     /** The begin of the rx rtp packet sequence number for Rtcp-Xr report */
286     int32_t mBeginSeq;
287     /** The end of the rx rtp packet sequence number for Rtcp-Xr report */
288     int32_t mEndSeq;
289     /** The call quality structure to report */
290     CallQuality mCallQuality;
291     /** The sum of the relative jitter of rx packet for call quality */
292     int64_t mCallQualitySumRelativeJitter;
293     /** The sum of the round trip delay of the session for call quality */
294     uint64_t mSumRoundTripTime;
295     /** The number of the round trip delay of the session for call quality */
296     uint32_t mCountRoundTripTime;
297     /** The current jitter buffer size in milliseconds unit */
298     uint32_t mCurrentBufferSize;
299     /** The maximum jitter buffer size in milliseconds unit */
300     uint32_t mMaxBufferSize;
301     /** The number of rx packet received for call quality calculation */
302     uint32_t mCallQualityNumRxPacket;
303     /** The number of lost rx packet for call quality calculation */
304     uint32_t mCallQualityNumLostPacket;
305     /** The number of dropped packets this period for call quality calculation */
306     uint32_t mCallQualityNumDroppedPacket;
307     /** The number of received packets this period for call quality inactivity */
308     uint32_t mCallQualityInactNumRxPacket;
309     /** The number of 1s periods without activity for call quality inactivity */
310     uint32_t mCallQualityNumInactPeriods;
311     /** The list of the playout delay of the audio frames */
312     std::list<uint32_t> mListPlayoutDelay;
313 
314     // MediaQualityThreshold parameters
315     std::vector<int32_t> mBaseRtpInactivityTimes;
316     std::vector<int32_t> mCurrentRtpInactivityTimes;
317     int32_t mRtcpInactivityTime;
318     int32_t mRtpHysteresisTime;
319     int32_t mPacketLossDuration;
320     std::vector<int32_t> mPacketLossThreshold;
321     std::vector<int32_t> mJitterThreshold;
322     bool mNotifyStatus;
323 
324     // Rtp Reception Statistics
325     int32_t mReceptionInterval;
326     int32_t mLatestRtcpSrTimestamp;
327     int64_t mLatestRtcpSrNtpTimestamp;
328     int32_t mLatestRoundTripDelayMs;
329 
330     // Counter for inactivity check
331     int32_t mCountRtpInactivity;
332     int32_t mCountRtcpInactivity;
333 
334     /** The MediaQualityStatus structure to report */
335     MediaQualityStatus mQualityStatus;
336 
337     /** The number of received packet to check packet loss notification */
338     uint32_t mNumRxPacket;
339     /** The number of lost packet to check packet loss notification */
340     uint32_t mNumLostPacket;
341     /** The cumulated jitter value when any rx packet received */
342     double mJitterRxPacket;
343     /** The number of rtcp packet received */
344     uint32_t mNumRtcpPacketReceived;
345 
346     HysteresisTimeChecker mPacketLossChecker;
347     HysteresisTimeChecker mJitterChecker;
348 
349     // event parameters
350     std::list<uint32_t> mListevent;
351     std::list<uint64_t> mListParamA;
352     std::list<uint64_t> mListParamB;
353     std::mutex mEventMutex;
354     ImsMediaCondition mConditionExit;
355     uint32_t mTimeFactor;
356 };
357 
358 #endif