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 [=](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 Check the audio config has different codec values 135 * 136 * @param config The AudioConfig to compare 137 */ 138 bool isSameConfig(AudioConfig* config); 139 140 /** 141 * @brief Start for calculating statistics from collected datas 142 */ 143 void start(); 144 145 /** 146 * @brief Stop calculating the statistics from collected datas and send a report 147 */ 148 void stop(); 149 150 /** 151 * @brief Collect information of sending or receiving the rtp or the rtcp packet datas. 152 * 153 * @param streamType The stream type. Tx, Rx, Rtcp. 154 * @param packet The packet data struct. 155 */ 156 void collectInfo(const int32_t streamType, RtpPacket* packet); 157 158 /** 159 * @brief Collect optional information of sending or receiving the rtp or rtcp packet datas. 160 * 161 * @param optionType The optional type to collect. The TTL or the Round Trip delay. 162 * @param seq The sequence number of the packet to collect. 163 * @param value The optional value to collect. 164 */ 165 void collectOptionalInfo(const int32_t optionType, const int32_t seq, const int32_t value); 166 167 /** 168 * @brief Collects Rtp status determined from the jitter buffer. 169 * 170 * @param seq The packet sequence number to collect. 171 * @param status The status of the packet. Check in @link{kRtpPacketStatus} 172 * @param time The time marked when the frame was played in milliseconds unit 173 */ 174 void collectRxRtpStatus(const int32_t seq, const kRtpPacketStatus status, const uint32_t time); 175 176 /** 177 * @brief Collects jitter buffer size. 178 * 179 * @param currSize The current size of the jitter buffer. 180 * @param maxSize The maximum jitter buffer size. 181 */ 182 void collectJitterBufferSize(const int32_t currSize, const int32_t maxSize); 183 184 /** 185 * @brief generate Rtcp-Xr report blocks with given report block enabled in bitmask type 186 * 187 * @param nReportBlocks The bitmask of report block to creates 188 * @param data The byte array of total report blocks 189 * @param size The size of total report blocks together 190 * @return true The report block is not zero and data is valid 191 * @return false The report block is zero or got error during create the report block 192 */ 193 bool getRtcpXrReportBlock(const uint32_t nReportBlocks, uint8_t* data, uint32_t& size); 194 195 /** 196 * @brief Get the CallQuality member instance 197 */ 198 CallQuality getCallQuality(); 199 200 /** 201 * @brief Get number of rx packets in the list 202 */ 203 uint32_t getRxPacketSize(); 204 205 /** 206 * @brief Get number of tx packets in the list 207 */ 208 uint32_t getTxPacketSize(); 209 210 /** 211 * @brief Get number of lost packets in the list 212 */ 213 uint32_t getLostPacketSize(); 214 215 /** 216 * @brief Send message event to event handler 217 * 218 * @param event The event type 219 * @param paramA The 1st parameter 220 * @param paramB The 2nd parameter 221 */ 222 void SendEvent(uint32_t event, uint64_t paramA, uint64_t paramB = 0); 223 224 protected: 225 /** 226 * @brief Process the data stacked in the list 227 * 228 * @param timeCount The count increased every second 229 */ 230 void processData(const int32_t timeCount); 231 void processMediaQuality(); 232 void notifyCallQuality(); 233 void notifyMediaQualityStatus(); 234 void AddEvent(uint32_t event, uint64_t paramA, uint64_t paramB); 235 void processEvent(uint32_t event, uint64_t paramA, uint64_t paramB); 236 virtual void* run(); 237 void reset(); 238 void clearPacketList(std::list<RtpPacket*>& list, const int32_t seq); 239 void clearLostPacketList(const int32_t seq); 240 uint32_t getCallQuality(double lossRate); 241 int32_t convertAudioCodecType(const int32_t codec, const int32_t bandwidth); 242 243 BaseSessionCallback* mCallback; 244 std::unique_ptr<RtcpXrEncoder> mRtcpXrEncoder; 245 /** The list of the packets received ordered by arrival time */ 246 std::list<RtpPacket*> mListRxPacket; 247 /** The list of the lost packets object */ 248 std::list<LostPacket*> mListLostPacket; 249 /** The list of the packets sent */ 250 std::list<RtpPacket*> mListTxPacket; 251 /** The time of call started in milliseconds unit*/ 252 int32_t mTimeStarted; 253 /** The ssrc of the receiving Rtp stream to identify */ 254 int32_t mSSRC; 255 /** The codec type of the audio session retrieved from the AudioConfig.h */ 256 int32_t mCodecType; 257 /** The codec attribute of the audio session, it could be bandwidth in evs codec */ 258 int32_t mCodecAttribute; 259 /** Whether RTP is activated for the receiver or not */ 260 bool mIsRxRtpEnabled; 261 /** Whether RTCP is activated for both sender and receiver */ 262 bool mIsRtcpEnabled; 263 /** The begin of the rx rtp packet sequence number for Rtcp-Xr report */ 264 int32_t mBeginSeq; 265 /** The end of the rx rtp packet sequence number for Rtcp-Xr report */ 266 int32_t mEndSeq; 267 /** The call quality structure to report */ 268 CallQuality mCallQuality; 269 /** The sum of the relative jitter of rx packet for call quality */ 270 int64_t mCallQualitySumRelativeJitter; 271 /** The sum of the round trip delay of the session for call quality */ 272 uint64_t mSumRoundTripTime; 273 /** The number of the round trip delay of the session for call quality */ 274 uint32_t mCountRoundTripTime; 275 /** The current jitter buffer size in milliseconds unit */ 276 uint32_t mCurrentBufferSize; 277 /** The maximum jitter buffer size in milliseconds unit */ 278 uint32_t mMaxBufferSize; 279 /** The number of rx packet received for call quality calculation */ 280 uint32_t mCallQualityNumRxPacket; 281 /** The number of lost rx packet for call quality calculation */ 282 uint32_t mCallQualityNumLostPacket; 283 284 // MediaQualityThreshold parameters 285 std::vector<int32_t> mBaseRtpInactivityTimes; 286 std::vector<int32_t> mCurrentRtpInactivityTimes; 287 int32_t mRtcpInactivityTime; 288 int32_t mRtpHysteresisTime; 289 int32_t mPacketLossDuration; 290 std::vector<int32_t> mPacketLossThreshold; 291 std::vector<int32_t> mJitterThreshold; 292 bool mNotifyStatus; 293 294 // Counter for inactivity check 295 int32_t mCountRtpInactivity; 296 int32_t mCountRtcpInactivity; 297 298 /** The MediaQualityStatus structure to report */ 299 MediaQualityStatus mQualityStatus; 300 301 /** The number of received packet to check packet loss notification */ 302 uint32_t mNumRxPacket; 303 /** The number of lost packet to check packet loss notification */ 304 uint32_t mNumLostPacket; 305 /** The cumulated jitter value when any rx packet received */ 306 double mJitterRxPacket; 307 /** The number of rtcp packet received */ 308 uint32_t mNumRtcpPacketReceived; 309 310 HysteresisTimeChecker mPacketLossChecker; 311 HysteresisTimeChecker mJitterChecker; 312 313 // event parameters 314 std::list<uint32_t> mListevent; 315 std::list<uint64_t> mListParamA; 316 std::list<uint64_t> mListParamB; 317 std::mutex mEventMutex; 318 ImsMediaCondition mConditionExit; 319 }; 320 321 #endif