statistics

This commit is contained in:
Gaelle Braud 2024-07-02 16:38:43 +02:00
parent 99061afc92
commit 61d63e5b82
16 changed files with 568 additions and 48 deletions

View file

@ -28,6 +28,59 @@
DEFINE_ABSTRACT_OBJECT(CallCore)
/***********************************************************************/
ZrtpStats ZrtpStats::operator=(ZrtpStats s) {
cipherAlgorithm = s.cipherAlgorithm;
keyAgreementAlgorithm = s.keyAgreementAlgorithm;
hashAlgorithm = s.hashAlgorithm;
authenticationAlgorithm = s.authenticationAlgorithm;
sasAlgorithm = s.sasAlgorithm;
isPostQuantum = s.isPostQuantum;
return *this;
}
bool ZrtpStats::operator==(ZrtpStats s) {
return s.cipherAlgorithm == cipherAlgorithm && s.keyAgreementAlgorithm == keyAgreementAlgorithm &&
s.hashAlgorithm == hashAlgorithm && s.authenticationAlgorithm == authenticationAlgorithm &&
s.sasAlgorithm == sasAlgorithm && s.isPostQuantum == isPostQuantum;
}
bool ZrtpStats::operator!=(ZrtpStats s) {
return s.cipherAlgorithm != cipherAlgorithm || s.keyAgreementAlgorithm != keyAgreementAlgorithm ||
s.hashAlgorithm != hashAlgorithm || s.authenticationAlgorithm != authenticationAlgorithm ||
s.sasAlgorithm != sasAlgorithm || s.isPostQuantum != isPostQuantum;
}
AudioStats AudioStats::operator=(AudioStats s) {
codec = s.codec;
bandwidth = s.bandwidth;
return *this;
}
bool AudioStats::operator==(AudioStats s) {
return s.codec == codec && s.bandwidth == bandwidth;
}
bool AudioStats::operator!=(AudioStats s) {
return s.codec != codec || s.bandwidth != bandwidth;
}
VideoStats VideoStats::operator=(VideoStats s) {
codec = s.codec;
bandwidth = s.bandwidth;
resolution = s.resolution;
fps = s.fps;
return *this;
}
bool VideoStats::operator==(VideoStats s) {
return s.codec == codec && s.bandwidth == bandwidth && s.resolution == resolution && s.fps == fps;
}
bool VideoStats::operator!=(VideoStats s) {
return s.codec != codec || s.bandwidth != bandwidth || s.resolution != resolution || s.fps != fps;
}
/***********************************************************************/
QVariant createDeviceVariant(const QString &id, const QString &name) {
QVariantMap map;
map.insert("id", id);
@ -72,6 +125,16 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
mIsSecured = (mEncryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) ||
mEncryption == LinphoneEnums::MediaEncryption::Srtp ||
mEncryption == LinphoneEnums::MediaEncryption::Dtls;
if (mEncryption == LinphoneEnums::MediaEncryption::Zrtp) {
auto stats = call->getStats(linphone::StreamType::Audio);
if (stats) {
mZrtpStats.cipherAlgorithm = Utils::coreStringToAppString(stats->getZrtpCipherAlgo());
mZrtpStats.keyAgreementAlgorithm = Utils::coreStringToAppString(stats->getZrtpKeyAgreementAlgo());
mZrtpStats.hashAlgorithm = Utils::coreStringToAppString(stats->getZrtpHashAlgo());
mZrtpStats.authenticationAlgorithm = Utils::coreStringToAppString(stats->getZrtpAuthTagAlgo());
mZrtpStats.sasAlgorithm = Utils::coreStringToAppString(stats->getZrtpSasAlgo());
}
}
auto conference = call->getConference();
mIsConference = conference != nullptr;
if (mIsConference) {
@ -158,7 +221,6 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
auto isMismatch = mCallModel->getZrtpCaseMismatch();
mCallModelConnection->invokeToCore([this, verified, isMismatch]() {
setTokenVerified(verified);
setIsSecured(verified && !isMismatch);
emit tokenVerified();
});
});
@ -172,6 +234,9 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
mCallModelConnection->makeConnectToModel(&CallModel::durationChanged, [this](int duration) {
mCallModelConnection->invokeToCore([this, duration]() { setDuration(duration); });
});
mCallModelConnection->makeConnectToModel(&CallModel::qualityUpdated, [this](float quality) {
mCallModelConnection->invokeToCore([this, quality]() { setCurrentQuality(quality); });
});
mCallModelConnection->makeConnectToModel(&CallModel::speakerVolumeGainChanged, [this](float volume) {
mCallModelConnection->invokeToCore([this, volume]() { setSpeakerVolumeGain(volume); });
});
@ -182,16 +247,11 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
mCallModelConnection->invokeToCore([this, volume]() { setMicrophoneVolume(volume); });
});
mCallModelConnection->makeConnectToModel(
&CallModel::stateChanged, [this](linphone::Call::State state, const std::string &message) {
&CallModel::stateChanged,
[this](std::shared_ptr<linphone::Call> call, linphone::Call::State state, const std::string &message) {
mCallModelConnection->invokeToCore([this, state, message]() {
setState(LinphoneEnums::fromLinphone(state), Utils::coreStringToAppString(message));
});
});
mCallModelConnection->makeConnectToModel(&CallModel::statusChanged, [this](linphone::Call::Status status) {
mCallModelConnection->invokeToCore([this, status]() { setStatus(LinphoneEnums::fromLinphone(status)); });
});
mCallModelConnection->makeConnectToModel(
&CallModel::stateChanged, [this](linphone::Call::State state, const std::string &message) {
double speakerVolume = mSpeakerVolumeGain;
double micVolume = mMicrophoneVolumeGain;
if (state == linphone::Call::State::StreamsRunning) {
@ -210,6 +270,9 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
setRecordable(state == linphone::Call::State::StreamsRunning);
});
});
mCallModelConnection->makeConnectToModel(&CallModel::statusChanged, [this](linphone::Call::Status status) {
mCallModelConnection->invokeToCore([this, status]() { setStatus(LinphoneEnums::fromLinphone(status)); });
});
mCallModelConnection->makeConnectToCore(&CallCore::lSetPaused, [this](bool paused) {
mCallModelConnection->invokeToModel([this, paused]() { mCallModel->setPaused(paused); });
});
@ -246,13 +309,18 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
setRemoteTokens(remoteTokens);
setEncryption(encryption);
setIsMismatch(isCaseMismatch);
setIsSecured(
(encryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified && !isCaseMismatch)); // ||
// encryption == LinphoneEnums::MediaEncryption::Srtp ||
// encryption == LinphoneEnums::MediaEncryption::Dtls);
// TODO : change this when api available in sdk
setTokenVerified(tokenVerified);
});
auto mediaEncryption = call->getParams()->getMediaEncryption();
if (mediaEncryption == linphone::MediaEncryption::ZRTP) {
auto stats = call->getAudioStats();
ZrtpStats zrtpStats;
zrtpStats.cipherAlgorithm = Utils::coreStringToAppString(stats->getZrtpCipherAlgo());
zrtpStats.keyAgreementAlgorithm = Utils::coreStringToAppString(stats->getZrtpKeyAgreementAlgo());
zrtpStats.hashAlgorithm = Utils::coreStringToAppString(stats->getZrtpHashAlgo());
zrtpStats.authenticationAlgorithm = Utils::coreStringToAppString(stats->getZrtpAuthTagAlgo());
zrtpStats.sasAlgorithm = Utils::coreStringToAppString(stats->getZrtpSasAlgo());
mCallModelConnection->invokeToCore([this, zrtpStats]() { setZrtpStats(zrtpStats); });
}
});
mCallModelConnection->makeConnectToCore(&CallCore::lSetSpeakerVolumeGain, [this](float gain) {
mCallModelConnection->invokeToModel([this, gain]() { mCallModel->setSpeakerVolumeGain(gain); });
@ -318,6 +386,52 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
auto core = VideoSourceDescriptorCore::create(videoSource ? videoSource->clone() : nullptr);
mCallModelConnection->invokeToCore([this, core]() { setVideoSourceDescriptor(core); });
});
mCallModelConnection->makeConnectToModel(
&CallModel::statsUpdated,
[this](const std::shared_ptr<linphone::Call> &call, const std::shared_ptr<const linphone::CallStats> &stats) {
if (stats->getType() == linphone::StreamType::Audio) {
AudioStats audioStats;
auto playloadType = call->getParams()->getUsedAudioPayloadType();
auto codecType = playloadType ? playloadType->getMimeType() : "";
auto codecRate = playloadType ? playloadType->getClockRate() / 1000 : 0;
audioStats.codec = tr("Codec: %1 / %2 kHz").arg(Utils::coreStringToAppString(codecType)).arg(codecRate);
if (stats) {
audioStats.bandwidth = tr("Bande passante : %1 %2 %3 %4")
.arg("")
.arg(stats->getUploadBandwidth())
.arg("")
.arg(stats->getDownloadBandwidth());
}
setAudioStats(audioStats);
} else if (stats->getType() == linphone::StreamType::Video) {
VideoStats videoStats;
auto params = call->getParams();
auto playloadType = params->getUsedAudioPayloadType();
auto codecType = playloadType ? playloadType->getMimeType() : "";
auto codecRate = playloadType ? playloadType->getClockRate() / 1000 : 0;
videoStats.codec = tr("Codec: %1 / %2 kHz").arg(Utils::coreStringToAppString(codecType)).arg(codecRate);
if (stats) {
videoStats.bandwidth = tr("Bande passante : %1 %2 %3 %4")
.arg("")
.arg(stats->getUploadBandwidth())
.arg("")
.arg(stats->getDownloadBandwidth());
}
auto sentResolution =
params->getSentVideoDefinition() ? params->getSentVideoDefinition()->getName() : "";
auto receivedResolution =
params->getReceivedVideoDefinition() ? params->getReceivedVideoDefinition()->getName() : "";
videoStats.resolution = tr("Définition vidéo : %1 %2 %3 %4")
.arg("")
.arg(Utils::coreStringToAppString(sentResolution))
.arg("")
.arg(Utils::coreStringToAppString(receivedResolution));
auto sentFps = params->getSentFramerate();
auto receivedFps = params->getReceivedFramerate();
videoStats.fps = tr("FPS : %1 %2 %3 %4").arg("").arg(sentFps).arg("").arg(receivedFps);
setVideoStats(videoStats);
}
});
}
QString CallCore::getPeerAddress() const {
@ -378,7 +492,7 @@ void CallCore::setLastErrorMessage(const QString &message) {
}
}
int CallCore::getDuration() {
int CallCore::getDuration() const {
return mDuration;
}
@ -389,6 +503,17 @@ void CallCore::setDuration(int duration) {
}
}
float CallCore::getCurrentQuality() const {
return mQuality;
}
void CallCore::setCurrentQuality(float quality) {
if (mQuality != quality) {
mQuality = quality;
emit qualityChanged(mQuality);
}
}
bool CallCore::getSpeakerMuted() const {
return mSpeakerMuted;
}
@ -445,17 +570,6 @@ void CallCore::setTokenVerified(bool verified) {
}
}
bool CallCore::isSecured() const {
return mIsSecured;
}
void CallCore::setIsSecured(bool secured) {
if (mIsSecured != secured) {
mIsSecured = secured;
emit securityUpdated();
}
}
bool CallCore::isMismatch() const {
return mIsMismatch;
}
@ -515,6 +629,10 @@ LinphoneEnums::MediaEncryption CallCore::getEncryption() const {
return mEncryption;
}
QString CallCore::getEncryptionString() const {
return LinphoneEnums::toString(mEncryption);
}
void CallCore::setEncryption(LinphoneEnums::MediaEncryption encryption) {
if (mEncryption != encryption) {
mEncryption = encryption;
@ -631,3 +749,36 @@ void CallCore::setConferenceVideoLayout(LinphoneEnums::ConferenceLayout layout)
std::shared_ptr<CallModel> CallCore::getModel() const {
return mCallModel;
}
ZrtpStats CallCore::getZrtpStats() const {
return mZrtpStats;
}
void CallCore::setZrtpStats(ZrtpStats stats) {
if (stats != mZrtpStats) {
mZrtpStats = stats;
emit zrtpStatsChanged();
}
}
AudioStats CallCore::getAudioStats() const {
return mAudioStats;
}
void CallCore::setAudioStats(AudioStats stats) {
if (stats != mAudioStats) {
mAudioStats = stats;
emit audioStatsChanged();
}
}
VideoStats CallCore::getVideoStats() const {
return mVideoStats;
}
void CallCore::setVideoStats(VideoStats stats) {
if (stats != mVideoStats) {
mVideoStats = stats;
emit videoStatsChanged();
}
}

View file

@ -31,6 +31,61 @@
#include <QSharedPointer>
#include <linphone++/linphone.hh>
struct ZrtpStats {
Q_GADGET
Q_PROPERTY(QString cipherAlgo MEMBER cipherAlgorithm)
Q_PROPERTY(QString keyAgreementAlgo MEMBER keyAgreementAlgorithm)
Q_PROPERTY(QString hashAlgo MEMBER hashAlgorithm)
Q_PROPERTY(QString authenticationAlgo MEMBER authenticationAlgorithm)
Q_PROPERTY(QString sasAlgo MEMBER sasAlgorithm)
Q_PROPERTY(bool isPostQuantum MEMBER isPostQuantum)
public:
bool isPostQuantum = false;
QString cipherAlgorithm;
QString keyAgreementAlgorithm;
QString hashAlgorithm;
QString authenticationAlgorithm;
QString sasAlgorithm;
ZrtpStats operator=(ZrtpStats s);
bool operator==(ZrtpStats s);
bool operator!=(ZrtpStats s);
};
struct AudioStats {
Q_GADGET
Q_PROPERTY(QString codec MEMBER codec)
Q_PROPERTY(QString bandwidth MEMBER bandwidth)
public:
QString codec;
QString bandwidth;
AudioStats operator=(AudioStats s);
bool operator==(AudioStats s);
bool operator!=(AudioStats s);
};
struct VideoStats {
Q_GADGET
Q_PROPERTY(QString codec MEMBER codec)
Q_PROPERTY(QString bandwidth MEMBER bandwidth)
Q_PROPERTY(QString resolution MEMBER resolution)
Q_PROPERTY(QString fps MEMBER fps)
public:
QString codec;
QString bandwidth;
QString resolution;
QString fps;
VideoStats operator=(VideoStats s);
bool operator==(VideoStats s);
bool operator!=(VideoStats s);
};
class CallCore : public QObject, public AbstractObject {
Q_OBJECT
@ -40,15 +95,16 @@ class CallCore : public QObject, public AbstractObject {
Q_PROPERTY(LinphoneEnums::CallState state READ getState NOTIFY stateChanged)
Q_PROPERTY(QString lastErrorMessage READ getLastErrorMessage NOTIFY lastErrorMessageChanged)
Q_PROPERTY(int duration READ getDuration NOTIFY durationChanged)
Q_PROPERTY(int quality READ getCurrentQuality NOTIFY qualityChanged)
Q_PROPERTY(bool speakerMuted READ getSpeakerMuted WRITE lSetSpeakerMuted NOTIFY speakerMutedChanged)
Q_PROPERTY(bool microphoneMuted READ getMicrophoneMuted WRITE lSetMicrophoneMuted NOTIFY microphoneMutedChanged)
Q_PROPERTY(bool paused READ getPaused WRITE lSetPaused NOTIFY pausedChanged)
Q_PROPERTY(QString peerAddress READ getPeerAddress CONSTANT)
Q_PROPERTY(QString localAddress READ getLocalAddress CONSTANT)
Q_PROPERTY(bool tokenVerified READ getTokenVerified WRITE setTokenVerified NOTIFY securityUpdated)
// Q_PROPERTY(bool isSecured READ isSecured WRITE setIsSecured NOTIFY securityUpdated)
Q_PROPERTY(bool isMismatch READ isMismatch WRITE setIsMismatch NOTIFY securityUpdated)
Q_PROPERTY(LinphoneEnums::MediaEncryption encryption READ getEncryption NOTIFY securityUpdated)
Q_PROPERTY(QString encryptionString READ getEncryptionString NOTIFY securityUpdated)
Q_PROPERTY(QString localToken READ getLocalToken WRITE setLocalToken MEMBER mLocalToken NOTIFY localTokenChanged)
Q_PROPERTY(QStringList remoteTokens WRITE setRemoteTokens MEMBER mRemoteTokens NOTIFY remoteTokensChanged)
Q_PROPERTY(
@ -71,6 +127,9 @@ class CallCore : public QObject, public AbstractObject {
Q_PROPERTY(VideoSourceDescriptorGui *videoSourceDescriptor READ getVideoSourceDescriptorGui WRITE
lSetVideoSourceDescriptor NOTIFY videoSourceDescriptorChanged)
Q_PROPERTY(ZrtpStats zrtpStats READ getZrtpStats WRITE setZrtpStats NOTIFY zrtpStatsChanged)
Q_PROPERTY(AudioStats audioStats READ getAudioStats WRITE setAudioStats NOTIFY audioStatsChanged)
Q_PROPERTY(VideoStats videoStats READ getVideoStats WRITE setVideoStats NOTIFY videoStatsChanged)
public:
// Should be call from model Thread. Will be automatically in App thread after initialization
@ -94,9 +153,12 @@ public:
QString getLastErrorMessage() const;
void setLastErrorMessage(const QString &message);
int getDuration();
int getDuration() const;
void setDuration(int duration);
float getCurrentQuality() const;
void setCurrentQuality(float quality);
bool getSpeakerMuted() const;
void setSpeakerMuted(bool isMuted);
@ -109,9 +171,6 @@ public:
bool getTokenVerified() const;
void setTokenVerified(bool verified);
bool isSecured() const;
void setIsSecured(bool secured);
bool isMismatch() const;
void setIsMismatch(bool mismatch);
@ -127,6 +186,7 @@ public:
void setRemoteTokens(const QStringList &Tokens);
LinphoneEnums::MediaEncryption getEncryption() const;
QString getEncryptionString() const;
void setEncryption(LinphoneEnums::MediaEncryption encryption);
bool getRemoteVideoEnabled() const;
@ -166,12 +226,23 @@ public:
void setVideoSourceDescriptor(QSharedPointer<VideoSourceDescriptorCore> core);
std::shared_ptr<CallModel> getModel() const;
ZrtpStats getZrtpStats() const;
void setZrtpStats(ZrtpStats stats);
AudioStats getAudioStats() const;
void setAudioStats(AudioStats stats);
VideoStats getVideoStats() const;
void setVideoStats(VideoStats stats);
signals:
void statusChanged(LinphoneEnums::CallStatus status);
void stateChanged(LinphoneEnums::CallState state);
void dirChanged(LinphoneEnums::CallDir dir);
void lastErrorMessageChanged();
void durationChanged(int duration);
void qualityChanged(float quality);
void speakerMutedChanged();
void microphoneMutedChanged();
void pausedChanged();
@ -191,6 +262,9 @@ signals:
void conferenceChanged();
void conferenceVideoLayoutChanged();
void videoSourceDescriptorChanged();
void zrtpStatsChanged();
void audioStatsChanged();
void videoStatsChanged();
// Linphone commands
void lAccept(bool withVideo); // Accept an incoming call
@ -250,6 +324,7 @@ private:
bool mIsSecured = false;
bool mIsMismatch = false;
int mDuration = 0;
float mQuality = 0;
bool mSpeakerMuted = false;
bool mMicrophoneMuted = false;
bool mLocalVideoEnabled = false;
@ -266,6 +341,9 @@ private:
float mMicrophoneVolume;
float mMicrophoneVolumeGain;
QSharedPointer<SafeConnection<CallCore, CallModel>> mCallModelConnection;
ZrtpStats mZrtpStats;
AudioStats mAudioStats;
VideoStats mVideoStats;
DECLARE_ABSTRACT_OBJECT
};

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#4e6074" viewBox="0 0 256 256"><path d="M168,72V200a8,8,0,0,1-16,0V72a8,8,0,0,1,16,0Zm32-48a8,8,0,0,0-8,8V200a8,8,0,0,0,16,0V32A8,8,0,0,0,200,24Zm-80,80a8,8,0,0,0-8,8v88a8,8,0,0,0,16,0V112A8,8,0,0,0,120,104ZM80,144a8,8,0,0,0-8,8v48a8,8,0,0,0,16,0V152A8,8,0,0,0,80,144ZM40,184a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-8A8,8,0,0,0,40,184Z"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M168,72V200a8,8,0,0,1-16,0V72a8,8,0,0,1,16,0Zm32-48a8,8,0,0,0-8,8V200a8,8,0,0,0,16,0V32A8,8,0,0,0,200,24Zm-80,80a8,8,0,0,0-8,8v88a8,8,0,0,0,16,0V112A8,8,0,0,0,120,104ZM80,144a8,8,0,0,0-8,8v48a8,8,0,0,0,16,0V152A8,8,0,0,0,80,144ZM40,184a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-8A8,8,0,0,0,40,184Z"></path></svg>

Before

Width:  |  Height:  |  Size: 411 B

After

Width:  |  Height:  |  Size: 411 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M168,72V200a8,8,0,0,1-16,0V72a8,8,0,0,1,16,0Zm-48,32a8,8,0,0,0-8,8v88a8,8,0,0,0,16,0V112A8,8,0,0,0,120,104ZM80,144a8,8,0,0,0-8,8v48a8,8,0,0,0,16,0V152A8,8,0,0,0,80,144ZM40,184a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-8A8,8,0,0,0,40,184Z"></path></svg>

After

Width:  |  Height:  |  Size: 351 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#4e6074" viewBox="0 0 256 256"><path d="M88,152v48a8,8,0,0,1-16,0V152a8,8,0,0,1,16,0ZM40,184a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-8A8,8,0,0,0,40,184Z"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M88,152v48a8,8,0,0,1-16,0V152a8,8,0,0,1,16,0ZM40,184a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-8A8,8,0,0,0,40,184Z"></path></svg>

Before

Width:  |  Height:  |  Size: 228 B

After

Width:  |  Height:  |  Size: 228 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M128,112v88a8,8,0,0,1-16,0V112a8,8,0,0,1,16,0ZM80,144a8,8,0,0,0-8,8v48a8,8,0,0,0,16,0V152A8,8,0,0,0,80,144ZM40,184a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-8A8,8,0,0,0,40,184Z"></path></svg>

After

Width:  |  Height:  |  Size: 290 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M48,192v8a8,8,0,0,1-16,0v-8a8,8,0,0,1,16,0Z"></path></svg>

After

Width:  |  Height:  |  Size: 167 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M88,152v48a8,8,0,0,1-16,0V152a8,8,0,0,1,16,0ZM40,184a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-8A8,8,0,0,0,40,184Zm173.92,26.62-160-176A8,8,0,1,0,42.08,45.38L112,122.29V200a8,8,0,0,0,16,0V139.89l24,26.4V200a8,8,0,0,0,16,0V183.89l34.08,37.49a8,8,0,1,0,11.84-10.76Zm-53.92-87a8,8,0,0,0,8-8V72a8,8,0,0,0-16,0v43.63A8,8,0,0,0,160,123.63Zm40,44a8,8,0,0,0,8-8V32a8,8,0,0,0-16,0V159.63A8,8,0,0,0,200,167.63Z"></path></svg>

After

Width:  |  Height:  |  Size: 514 B

View file

@ -35,6 +35,7 @@ CallModel::CallModel(const std::shared_ptr<linphone::Call> &call, QObject *paren
mDurationTimer.setInterval(1000);
mDurationTimer.setSingleShot(false);
connect(&mDurationTimer, &QTimer::timeout, this, [this]() { this->durationChanged(mMonitor->getDuration()); });
connect(&mDurationTimer, &QTimer::timeout, this, [this]() { this->qualityUpdated(mMonitor->getCurrentQuality()); });
mDurationTimer.start();
mMicroVolumeTimer.setInterval(50);
@ -302,6 +303,18 @@ void CallModel::setConference(const std::shared_ptr<linphone::Conference> &confe
}
}
std::shared_ptr<linphone::CallStats> CallModel::getAudioStats() const {
return mMonitor->getAudioStats();
}
std::shared_ptr<linphone::CallStats> CallModel::getVideoStats() const {
return mMonitor->getVideoStats();
}
std::shared_ptr<linphone::CallStats> CallModel::getTextStats() const {
return mMonitor->getTextStats();
}
LinphoneEnums::ConferenceLayout CallModel::getConferenceVideoLayout() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return LinphoneEnums::fromLinphone(mMonitor->getParams()->getConferenceVideoLayout());
@ -416,7 +429,7 @@ void CallModel::onStateChanged(const std::shared_ptr<linphone::Call> &call,
setConference(call->getConference());
updateConferenceVideoLayout();
}
emit stateChanged(state, message);
emit stateChanged(call, state, message);
}
void CallModel::onStatusChanged(const std::shared_ptr<linphone::Call> &call, linphone::Call::Status status) {

View file

@ -55,6 +55,9 @@ public:
void setOutputAudioDevice(const std::shared_ptr<linphone::AudioDevice> &id);
std::shared_ptr<const linphone::AudioDevice> getOutputAudioDevice() const;
void setConference(const std::shared_ptr<linphone::Conference> &conference);
std::shared_ptr<linphone::CallStats> getAudioStats() const;
std::shared_ptr<linphone::CallStats> getVideoStats() const;
std::shared_ptr<linphone::CallStats> getTextStats() const;
void setPaused(bool paused);
void transferTo(const std::shared_ptr<linphone::Address> &address);
@ -89,6 +92,7 @@ signals:
void microphoneMutedChanged(bool isMuted);
void speakerMutedChanged(bool isMuted);
void durationChanged(int);
void qualityUpdated(float quality);
void microphoneVolumeChanged(float);
void pausedChanged(bool paused);
void remoteVideoEnabledChanged(bool remoteVideoEnabled);
@ -156,7 +160,8 @@ signals:
void receiveMasterKeyChanged(const std::shared_ptr<linphone::Call> &call, const std::string &receiveMasterKey);
void infoMessageReceived(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::InfoMessage> &message);
void stateChanged(linphone::Call::State state, const std::string &message);
void
stateChanged(const std::shared_ptr<linphone::Call> &call, linphone::Call::State state, const std::string &message);
void statusChanged(linphone::Call::Status status);
void dirChanged(linphone::Call::Dir dir);
void statsUpdated(const std::shared_ptr<linphone::Call> &call,

View file

@ -54,6 +54,20 @@ linphone::MediaEncryption LinphoneEnums::toLinphone(const LinphoneEnums::MediaEn
LinphoneEnums::MediaEncryption LinphoneEnums::fromLinphone(const linphone::MediaEncryption &data) {
return static_cast<LinphoneEnums::MediaEncryption>(data);
}
QString LinphoneEnums::toString(LinphoneEnums::MediaEncryption encryption) {
switch (encryption) {
case LinphoneEnums::MediaEncryption::Dtls:
return "DTLS";
case LinphoneEnums::MediaEncryption::None:
return "None";
case LinphoneEnums::MediaEncryption::Srtp:
return "SRTP";
case LinphoneEnums::MediaEncryption::Zrtp:
return "ZRTP";
default:
return QString();
}
}
linphone::Friend::Capability LinphoneEnums::toLinphone(const LinphoneEnums::FriendCapability &data) {
return static_cast<linphone::Friend::Capability>(data);

View file

@ -44,6 +44,7 @@ Q_ENUM_NS(MediaEncryption)
linphone::MediaEncryption toLinphone(const LinphoneEnums::MediaEncryption &encryption);
LinphoneEnums::MediaEncryption fromLinphone(const linphone::MediaEncryption &encryption);
QString toString(LinphoneEnums::MediaEncryption encryption);
enum class FriendCapability {
None = int(linphone::Friend::Capability::None),

View file

@ -116,16 +116,21 @@ AppWindow {
target: call && call.core
onRemoteVideoEnabledChanged: console.log("remote video enabled", call.core.remoteVideoEnabled)
onSecurityUpdated: {
if (call.core.isSecured) {
if (call.core.encryption != LinphoneEnums.MediaEncryption.Zrtp || call.core.tokenVerified) {
zrtpValidation.close()
}
else if(call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp) {
zrtpValidation.open()
// mainWindow.attachVirtualWindow(Utils.buildLinphoneDialogUri('ZrtpTokenAuthenticationDialog'), {call:callModel})
}
}
}
Component.onCompleted: {
if(call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp && (!call.core.tokenVerified || call.core.isMismatch)) {
zrtpValidation.open()
}
}
Timer {
id: autoCloseWindow
interval: 2000
@ -237,7 +242,7 @@ AppWindow {
}
}
}
/************************* CONTENT ********************************/
Rectangle {
anchors.fill: parent
color: DefaultStyle.grey_900
@ -387,6 +392,10 @@ AppWindow {
anchors.fill: parent
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
rightPanel.visible = true
rightPanel.replace(encryptionPanel)
}
}
}
Item {
@ -397,8 +406,31 @@ AppWindow {
Item {
Layout.fillWidth: true
}
Item {
//TODO : network quality display
EffectImage {
Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.preferredHeight: 32 * DefaultStyle.dp
Layout.rightMargin: 30 * DefaultStyle.dp
property int quality: mainWindow.call ? mainWindow.call.core.quality : 0
imageSource: quality >= 4
? AppIcons.cellSignalFull
: quality >= 3
? AppIcons.cellSignalMedium
: quality >= 2
? AppIcons.cellSignalLow
: AppIcons.cellSignalNone
colorizationColor: DefaultStyle.grey_0
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (rightPanel.visible) rightPanel.visible = false
else {
rightPanel.visible = true
rightPanel.replace(statsPanel)
}
}
}
}
}
@ -882,12 +914,227 @@ AppWindow {
}
}
}
Component {
id: encryptionPanel
ColumnLayout {
Control.StackView.onActivated: {
rightPanel.headerTitleText = qsTr("Chiffrement")
}
RoundedBackgroundControl {
Layout.fillWidth: true
leftPadding: 16 * DefaultStyle.dp
rightPadding: 16 * DefaultStyle.dp
topPadding: 13 * DefaultStyle.dp
bottomPadding: 13 * DefaultStyle.dp
Layout.topMargin: 13 * DefaultStyle.dp
Layout.leftMargin: 16 * DefaultStyle.dp
Layout.rightMargin: 16 * DefaultStyle.dp
contentItem: ColumnLayout {
spacing: 12 * DefaultStyle.dp
Text {
text: qsTr("Chiffrement :")
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 7 * DefaultStyle.dp
Text {
property bool isPostQuantum: mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp && mainWindow.call.core.zrtpStats.isPostQuantum
text: qsTr("Chiffrement du média : %1%2").arg(isPostQuantum ? "post Quantum " : "").arg(mainWindow.call.core.encryptionString)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
ColumnLayout {
visible: mainWindow.call && mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp
Text {
text: qsTr("Cipher algorithm : %1").arg(mainWindow.call && mainWindow.call.core.zrtpStats.cipherAlgo)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: qsTr("Key agreement algorithm : %1").arg(mainWindow.call && mainWindow.call.core.zrtpStats.keyAgreementAlgo)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: qsTr("Hash algorithm : %1").arg(mainWindow.call && mainWindow.call.core.zrtpStats.hashAlgo)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: qsTr("Authentication algorithm : %1").arg(mainWindow.call && mainWindow.call.core.zrtpStats.authenticationAlgo)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: qsTr("SAS algorithm : %1").arg(mainWindow.call && mainWindow.call.core.zrtpStats.sasAlgo)
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
}
}
}
}
Item{Layout.fillHeight: true}
Button {
visible: mainWindow.call && mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp
Layout.fillWidth: true
text: qsTr("Validation chiffrement")
onClicked: zrtpValidation.open()
Layout.bottomMargin: 13 * DefaultStyle.dp
Layout.leftMargin: 16 * DefaultStyle.dp
Layout.rightMargin: 16 * DefaultStyle.dp
leftPadding: 20 * DefaultStyle.dp
rightPadding: 20 * DefaultStyle.dp
topPadding: 11 * DefaultStyle.dp
bottomPadding: 11 * DefaultStyle.dp
}
}
}
Component {
id: statsPanel
ColumnLayout {
spacing: 20 * DefaultStyle.dp
Control.StackView.onActivated: {
rightPanel.headerTitleText = qsTr("Statistiques")
}
RoundedBackgroundControl {
Layout.fillWidth: true
leftPadding: 16 * DefaultStyle.dp
rightPadding: 16 * DefaultStyle.dp
topPadding: 13 * DefaultStyle.dp
bottomPadding: 13 * DefaultStyle.dp
Layout.topMargin: 13 * DefaultStyle.dp
Layout.leftMargin: 16 * DefaultStyle.dp
Layout.rightMargin: 16 * DefaultStyle.dp
contentItem: ColumnLayout {
spacing: 12 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
Text {
text: qsTr("Audio")
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
ColumnLayout {
spacing: 7 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
Text {
text: mainWindow.call ? mainWindow.call.core.audioStats.codec : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: mainWindow.call ? mainWindow.call.core.audioStats.bandwidth : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
}
}
}
RoundedBackgroundControl {
Layout.fillWidth: true
leftPadding: 16 * DefaultStyle.dp
rightPadding: 16 * DefaultStyle.dp
topPadding: 13 * DefaultStyle.dp
bottomPadding: 13 * DefaultStyle.dp
Layout.topMargin: 13 * DefaultStyle.dp
Layout.leftMargin: 16 * DefaultStyle.dp
Layout.rightMargin: 16 * DefaultStyle.dp
contentItem: ColumnLayout {
spacing: 12 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
Text {
text: qsTr("Vidéo")
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp
}
}
ColumnLayout {
spacing: 7 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
Text {
text: mainWindow.call ? mainWindow.call.core.videoStats.codec : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: mainWindow.call ? mainWindow.call.core.videoStats.bandwidth : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: mainWindow.call ? mainWindow.call.core.videoStats.resolution : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
Text {
text: mainWindow.call ? mainWindow.call.core.videoStats.fps : ""
Layout.alignment: Qt.AlignHCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp
}
}
}
}
}
Item{Layout.fillHeight: true}
}
}
}
Component {
id: waitingRoom
WaitingRoom {
id: waitingRoomIn
Layout.alignment: Qt.AlignCenter
Layout.alignment: Qt.AlignCenter
onSettingsButtonCheckedChanged: {
if (settingsButtonChecked) {
rightPanel.visible = true

View file

@ -56,7 +56,7 @@ Control.Page {
Layout.fillHeight: true
Layout.alignment: Qt.AlignVCenter
verticalAlignment: Text.AlignVCenter
color: mainWindow.conference ? DefaultStyle.main1_500_main : DefaultStyle.main2_700
color: DefaultStyle.main1_500_main
font {
pixelSize: 16 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp

View file

@ -28,9 +28,11 @@ Dialog {
target: call && call.core
onStatusChanged: if (status === CallModel.CallStatusEnded) close()
onSecurityUpdated: {
if (!mainItem.isTokenVerified) {
mainItem.securityError = true
} else close()
if (mainItem.isTokenVerified) {
close()
// mainItem.securityError = true
// } else close()
}
}
onTokenVerified: {
if (!mainItem.isTokenVerified) {
@ -58,8 +60,8 @@ Dialog {
anchors.horizontalCenter: parent.horizontalCenter
Item {
// spacing: 14 * DefaultStyle.dp
width: childrenRect.width
height: childrenRect.height
Layout.Layout.preferredWidth: childrenRect.width
Layout.Layout.preferredHeight: childrenRect.height
Layout.Layout.fillWidth: true
Image {
id: trustShield
@ -221,7 +223,7 @@ Dialog {
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
console.log("check token", modelData)
console.log("CHECK TOKEN", modelData)
if(mainItem.call) mainItem.call.core.lCheckAuthenticationTokenSelected(modelData)
}
}

View file

@ -104,4 +104,9 @@ QtObject {
property string detective: "image://internal/detective.svg"
property string warningCircle: "image://internal/warning-circle.svg"
property string fullscreen: "image://internal/fullscreen.svg"
property string cellSignalFull: "image://internal/cell-signal-full.svg"
property string cellSignalHigh: "image://internal/cell-signal-high.svg"
property string cellSignalMedium: "image://internal/cell-signal-medium.svg"
property string cellSignalLow: "image://internal/cell-signal-low.svg"
property string cellSignalNone: "image://internal/cell-signal-none.svg"
}