blob: 29f0bb48d9901f28da0658a1c61d32a59b29ca30 [file] [log] [blame]
/**
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MEDIA_QUALITY_ANALYZER_H_INCLUDED
#define MEDIA_QUALITY_ANALYZER_H_INCLUDED
#include <CallQuality.h>
#include <ImsMediaDefine.h>
#include <IImsMediaThread.h>
#include <ImsMediaCondition.h>
#include <RtcpXrEncoder.h>
#include <BaseSessionCallback.h>
#include <AudioConfig.h>
#include <MediaQualityThreshold.h>
#include <MediaQualityStatus.h>
#include <list>
#include <vector>
#include <mutex>
#include <algorithm>
class HysteresisTimeChecker
{
public:
HysteresisTimeChecker(int32_t time = 0)
{
hysteresisTime = time;
countHysteresisTime = hysteresisTime;
notifiedDirection = 1;
firstNotified = false;
previousValue = 0;
}
void initialize(int32_t time)
{
hysteresisTime = time;
countHysteresisTime = hysteresisTime;
notifiedDirection = 1;
firstNotified = false;
previousValue = 0;
}
~HysteresisTimeChecker() {}
bool checkNotifiable(std::vector<int32_t> thresholds, int32_t currentValue)
{
if (thresholds.empty())
{
return false;
}
bool notifiable = false;
// cross the threshold case
auto iterCrossed = find_if(thresholds.begin(), thresholds.end(),
[=](int32_t thres)
{
return ((currentValue >= thres && previousValue < thres) ||
(currentValue < thres && previousValue >= thres));
});
if (iterCrossed != thresholds.end())
{
uint32_t currentDirection = (currentValue - previousValue) > 0 ? 1 : 0;
if (countHysteresisTime >= hysteresisTime || currentDirection == notifiedDirection)
{
if (!firstNotified)
{
firstNotified = true;
}
previousValue = currentValue;
countHysteresisTime = 0;
notifiedDirection = currentDirection;
notifiable = true;
}
countHysteresisTime++;
}
else
{
if (firstNotified)
{
countHysteresisTime = 1;
}
}
return notifiable;
}
int32_t hysteresisTime;
int32_t countHysteresisTime;
int32_t previousValue;
uint32_t notifiedDirection;
bool firstNotified;
};
class MediaQualityAnalyzer : public IImsMediaThread
{
public:
MediaQualityAnalyzer();
virtual ~MediaQualityAnalyzer();
/**
* @brief Set the session callback to send the event
*/
void setCallback(BaseSessionCallback* callback);
/**
* @brief Sets the audio codec type
* @param config The AudioConfig to set
*/
void setConfig(AudioConfig* config);
/**
* @brief Set the MediaQualityThreshold
*/
void setMediaQualityThreshold(const MediaQualityThreshold& threshold);
/**
* @brief Check the audio config has different codec values
*
* @param config The AudioConfig to compare
*/
bool isSameConfig(AudioConfig* config);
/**
* @brief Start for calculating statistics from collected datas
*/
void start();
/**
* @brief Stop calculating the statistics from collected datas and send a report
*/
void stop();
/**
* @brief Collect information of sending or receiving the rtp or the rtcp packet datas.
*
* @param streamType The stream type. Tx, Rx, Rtcp.
* @param packet The packet data struct.
*/
void collectInfo(const int32_t streamType, RtpPacket* packet);
/**
* @brief Collect optional information of sending or receiving the rtp or rtcp packet datas.
*
* @param optionType The optional type to collect. The TTL or the Round Trip delay.
* @param seq The sequence number of the packet to collect.
* @param value The optional value to collect.
*/
void collectOptionalInfo(const int32_t optionType, const int32_t seq, const int32_t value);
/**
* @brief Collects Rtp status determined from the jitter buffer.
*
* @param seq The packet sequence number to collect.
* @param status The status of the packet. Check in @link{kRtpPacketStatus}
* @param time The time marked when the frame was played in milliseconds unit
*/
void collectRxRtpStatus(const int32_t seq, const kRtpPacketStatus status, const uint32_t time);
/**
* @brief Collects jitter buffer size.
*
* @param currSize The current size of the jitter buffer.
* @param maxSize The maximum jitter buffer size.
*/
void collectJitterBufferSize(const int32_t currSize, const int32_t maxSize);
/**
* @brief generate Rtcp-Xr report blocks with given report block enabled in bitmask type
*
* @param nReportBlocks The bitmask of report block to creates
* @param data The byte array of total report blocks
* @param size The size of total report blocks together
* @return true The report block is not zero and data is valid
* @return false The report block is zero or got error during create the report block
*/
bool getRtcpXrReportBlock(const uint32_t nReportBlocks, uint8_t* data, uint32_t& size);
/**
* @brief Get the CallQuality member instance
*/
CallQuality getCallQuality();
/**
* @brief Get number of rx packets in the list
*/
uint32_t getRxPacketSize();
/**
* @brief Get number of tx packets in the list
*/
uint32_t getTxPacketSize();
/**
* @brief Get number of lost packets in the list
*/
uint32_t getLostPacketSize();
/**
* @brief Send message event to event handler
*
* @param event The event type
* @param paramA The 1st parameter
* @param paramB The 2nd parameter
*/
void SendEvent(uint32_t event, uint64_t paramA, uint64_t paramB = 0);
protected:
/**
* @brief Process the data stacked in the list
*
* @param timeCount The count increased every second
*/
void processData(const int32_t timeCount);
void processMediaQuality();
void notifyMediaQualityStatus();
void AddEvent(uint32_t event, uint64_t paramA, uint64_t paramB);
void processEvent(uint32_t event, uint64_t paramA, uint64_t paramB);
virtual void* run();
void reset();
void clearPacketList(std::list<RtpPacket*>& list, const int32_t seq);
void clearLostPacketList(const int32_t seq);
uint32_t getCallQuality(double lossRate);
int32_t convertAudioCodecType(const int32_t codec, const int32_t bandwidth);
BaseSessionCallback* mCallback;
std::unique_ptr<RtcpXrEncoder> mRtcpXrEncoder;
/** The list of the packets received ordered by arrival time */
std::list<RtpPacket*> mListRxPacket;
/** The list of the lost packets object */
std::list<LostPacket*> mListLostPacket;
/** The list of the packets sent */
std::list<RtpPacket*> mListTxPacket;
/** The ssrc of the receiving Rtp stream to identify */
int32_t mSSRC;
/** The codec type of the audio session retrieved from the AudioConfig.h */
int32_t mCodecType;
/** The codec attribute of the audio session, it could be bandwidth in evs codec */
int32_t mCodecAttribute;
/** The begin of the rx rtp packet sequence number for Rtcp-Xr report */
int32_t mBeginSeq;
/** The end of the rx rtp packet sequence number for Rtcp-Xr report */
int32_t mEndSeq;
/** The call quality structure to report */
CallQuality mCallQuality;
/** The sum of the relative jitter of rx packet for call quality */
int64_t mCallQualitySumRelativeJitter;
/** The sum of the round trip delay of the session for call quality */
uint64_t mSumRoundTripTime;
/** The number of the round trip delay of the session for call quality */
uint32_t mCountRoundTripTime;
/** The current jitter buffer size in milliseconds unit */
uint32_t mCurrentBufferSize;
/** The maximum jitter buffer size in milliseconds unit */
uint32_t mMaxBufferSize;
/** The number of rx packet received for call quality calculation */
uint32_t mCallQualityNumRxPacket;
/** The number of lost rx packet for call quality calculation */
uint32_t mCallQualityNumLostPacket;
// MediaQualityThreshold parameters
std::vector<int32_t> mBaseRtpInactivityTimes;
std::vector<int32_t> mCurrentRtpInactivityTimes;
int32_t mRtcpInactivityTime;
int32_t mRtpHysteresisTime;
int32_t mPacketLossDuration;
std::vector<int32_t> mPacketLossThreshold;
std::vector<int32_t> mJitterThreshold;
bool mNotifyStatus;
// Counter for inactivity check
int32_t mCountRtpInactivity;
int32_t mCountRtcpInactivity;
/** The MediaQualityStatus structure to report */
MediaQualityStatus mQualityStatus;
/** The number of received packet to check packet loss notification */
uint32_t mNumRxPacket;
/** The number of lost packet to check packet loss notification */
uint32_t mNumLostPacket;
/** The cumulated jitter value when any rx packet received */
double mJitterRxPacket;
/** The number of rtcp packet received */
uint32_t mNumRtcpPacketReceived;
HysteresisTimeChecker mPacketLossChecker;
HysteresisTimeChecker mJitterChecker;
// event parameters
std::list<uint32_t> mListevent;
std::list<uint64_t> mListParamA;
std::list<uint64_t> mListParamB;
std::mutex mEventMutex;
ImsMediaCondition mConditionExit;
};
#endif