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