H264 Downloadable codec
This commit is contained in:
parent
85ca6d79ce
commit
425751413d
29 changed files with 1262 additions and 58 deletions
|
|
@ -433,8 +433,11 @@ void App::initCore() {
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
mLinphoneThread->getThreadId(),
|
mLinphoneThread->getThreadId(),
|
||||||
[this]() mutable {
|
[this]() mutable {
|
||||||
|
lInfo() << log().arg("Updating downloaded codec files");
|
||||||
|
Utils::updateCodecs(); // removing codec updates suffic (.in) before the core is created.
|
||||||
lInfo() << log().arg("Starting Core");
|
lInfo() << log().arg("Starting Core");
|
||||||
CoreModel::getInstance()->start();
|
CoreModel::getInstance()->start();
|
||||||
|
Utils::loadDownloadedCodecs();
|
||||||
auto coreStarted = CoreModel::getInstance()->getCore()->getGlobalState() == linphone::GlobalState::On;
|
auto coreStarted = CoreModel::getInstance()->getCore()->getGlobalState() == linphone::GlobalState::On;
|
||||||
lDebug() << log().arg("Creating SettingsModel");
|
lDebug() << log().arg("Creating SettingsModel");
|
||||||
SettingsModel::create();
|
SettingsModel::create();
|
||||||
|
|
@ -541,6 +544,8 @@ void App::initCore() {
|
||||||
},
|
},
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
|
Utils::checkDownloadedCodecsUpdates();
|
||||||
|
|
||||||
mEngine->load(url);
|
mEngine->load(url);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -631,6 +636,7 @@ void App::initCppInterfaces() {
|
||||||
qmlRegisterType<PayloadTypeGui>(Constants::MainQmlUri, 1, 0, "PayloadTypeGui");
|
qmlRegisterType<PayloadTypeGui>(Constants::MainQmlUri, 1, 0, "PayloadTypeGui");
|
||||||
qmlRegisterType<PayloadTypeProxy>(Constants::MainQmlUri, 1, 0, "PayloadTypeProxy");
|
qmlRegisterType<PayloadTypeProxy>(Constants::MainQmlUri, 1, 0, "PayloadTypeProxy");
|
||||||
qmlRegisterType<PayloadTypeCore>(Constants::MainQmlUri, 1, 0, "PayloadTypeCore");
|
qmlRegisterType<PayloadTypeCore>(Constants::MainQmlUri, 1, 0, "PayloadTypeCore");
|
||||||
|
qmlRegisterType<PayloadTypeCore>(Constants::MainQmlUri, 1, 0, "DownloadablePayloadTypeCore");
|
||||||
|
|
||||||
LinphoneEnums::registerMetaTypes();
|
LinphoneEnums::registerMetaTypes();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ list(APPEND _LINPHONEAPP_SOURCES
|
||||||
core/address-books/carddav/CarddavList.cpp
|
core/address-books/carddav/CarddavList.cpp
|
||||||
|
|
||||||
core/payload-type/PayloadTypeCore.cpp
|
core/payload-type/PayloadTypeCore.cpp
|
||||||
|
core/payload-type/DownloadablePayloadTypeCore.cpp
|
||||||
core/payload-type/PayloadTypeGui.cpp
|
core/payload-type/PayloadTypeGui.cpp
|
||||||
core/payload-type/PayloadTypeProxy.cpp
|
core/payload-type/PayloadTypeProxy.cpp
|
||||||
core/payload-type/PayloadTypeList.cpp
|
core/payload-type/PayloadTypeList.cpp
|
||||||
|
|
|
||||||
142
Linphone/core/payload-type/DownloadablePayloadTypeCore.cpp
Normal file
142
Linphone/core/payload-type/DownloadablePayloadTypeCore.cpp
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-desktop
|
||||||
|
* (see https://www.linphone.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DownloadablePayloadTypeCore.hpp"
|
||||||
|
#include "core/App.hpp"
|
||||||
|
#include "core/path/Paths.hpp"
|
||||||
|
#include "tool/file/FileDownloader.hpp"
|
||||||
|
#include "tool/file/FileExtractor.hpp"
|
||||||
|
|
||||||
|
DEFINE_ABSTRACT_OBJECT(DownloadablePayloadTypeCore)
|
||||||
|
|
||||||
|
QSharedPointer<DownloadablePayloadTypeCore> DownloadablePayloadTypeCore::create(PayloadTypeCore::Family family,
|
||||||
|
const QString &mimeType,
|
||||||
|
const QString &encoderDescription,
|
||||||
|
const QString &downloadUrl,
|
||||||
|
const QString &installName,
|
||||||
|
const QString &checkSum) {
|
||||||
|
auto sharedPointer = QSharedPointer<DownloadablePayloadTypeCore>(
|
||||||
|
new DownloadablePayloadTypeCore(family, mimeType, encoderDescription, downloadUrl, installName, checkSum),
|
||||||
|
&QObject::deleteLater);
|
||||||
|
sharedPointer->moveToThread(App::getInstance()->thread());
|
||||||
|
return sharedPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadablePayloadTypeCore::DownloadablePayloadTypeCore(PayloadTypeCore::Family family,
|
||||||
|
const QString &mimeType,
|
||||||
|
const QString &encoderDescription,
|
||||||
|
const QString &downloadUrl,
|
||||||
|
const QString &installName,
|
||||||
|
const QString &checkSum)
|
||||||
|
: PayloadTypeCore() {
|
||||||
|
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||||
|
|
||||||
|
mFamily = family;
|
||||||
|
mMimeType = mimeType;
|
||||||
|
mEnabled = false;
|
||||||
|
mDownloadable = true;
|
||||||
|
|
||||||
|
mEncoderDescription = encoderDescription;
|
||||||
|
mDownloadUrl = downloadUrl;
|
||||||
|
mInstallName = installName;
|
||||||
|
mCheckSum = checkSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadablePayloadTypeCore::~DownloadablePayloadTypeCore() {
|
||||||
|
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadablePayloadTypeCore::downloadAndExtract(bool isUpdate) {
|
||||||
|
lInfo() << log().arg("Downloading `%1` codec...").arg(mMimeType);
|
||||||
|
auto codecsFolder = Paths::getCodecsDirPath();
|
||||||
|
QString versionFilePath = codecsFolder + mMimeType + ".txt";
|
||||||
|
QFile versionFile(versionFilePath);
|
||||||
|
|
||||||
|
FileDownloader *fileDownloader = new FileDownloader(this);
|
||||||
|
fileDownloader->setUrl(QUrl(mDownloadUrl));
|
||||||
|
fileDownloader->setDownloadFolder(codecsFolder);
|
||||||
|
|
||||||
|
FileExtractor *fileExtractor = new FileExtractor(fileDownloader);
|
||||||
|
fileExtractor->setExtractFolder(codecsFolder);
|
||||||
|
fileExtractor->setExtractName(mInstallName + (isUpdate ? ".in" : ""));
|
||||||
|
|
||||||
|
QObject::connect(fileDownloader, &FileDownloader::downloadFinished,
|
||||||
|
[this, fileDownloader, fileExtractor, checksum = mCheckSum](const QString &filePath) {
|
||||||
|
fileExtractor->setFile(filePath);
|
||||||
|
QString fileChecksum = Utils::getFileChecksum(filePath);
|
||||||
|
if (checksum.isEmpty() || fileChecksum == checksum) fileExtractor->extract();
|
||||||
|
else {
|
||||||
|
lWarning() << log().arg("File cannot be downloaded : Bad checksum : ") << fileChecksum;
|
||||||
|
fileDownloader->remove();
|
||||||
|
fileDownloader->deleteLater();
|
||||||
|
emit downloadError();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(fileDownloader, &FileDownloader::downloadFailed, [this, fileDownloader]() {
|
||||||
|
fileDownloader->deleteLater();
|
||||||
|
emit downloadError();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(fileExtractor, &FileExtractor::extractFinished,
|
||||||
|
[this, fileDownloader, fileExtractor, versionFilePath, downloadUrl = mDownloadUrl]() {
|
||||||
|
QFile versionFile(versionFilePath);
|
||||||
|
if (!versionFile.open(QIODevice::WriteOnly)) {
|
||||||
|
lWarning() << log().arg("Unable to write codec version in: `%1`.").arg(versionFilePath);
|
||||||
|
emit extractError();
|
||||||
|
} else if (versionFile.write(Utils::appStringToCoreString(downloadUrl).c_str(),
|
||||||
|
downloadUrl.length()) == -1) {
|
||||||
|
fileExtractor->remove();
|
||||||
|
versionFile.close();
|
||||||
|
versionFile.remove();
|
||||||
|
emit extractError();
|
||||||
|
} else emit success();
|
||||||
|
fileDownloader->remove();
|
||||||
|
fileDownloader->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(fileExtractor, &FileExtractor::extractFailed, [this, fileDownloader]() {
|
||||||
|
fileDownloader->remove();
|
||||||
|
fileDownloader->deleteLater();
|
||||||
|
emit extractError();
|
||||||
|
});
|
||||||
|
|
||||||
|
fileDownloader->download();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DownloadablePayloadTypeCore::shouldDownloadUpdate() {
|
||||||
|
auto codecsFolder = Paths::getCodecsDirPath();
|
||||||
|
QString versionFilePath = codecsFolder + mMimeType + ".txt";
|
||||||
|
QFile versionFile(versionFilePath);
|
||||||
|
|
||||||
|
if (!versionFile.exists() && !QFileInfo::exists(codecsFolder + mInstallName)) {
|
||||||
|
lWarning() << log().arg("Codec `%1` is not installed.").arg(versionFilePath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!versionFile.open(QIODevice::ReadOnly)) {
|
||||||
|
lWarning() << log().arg("Codec `%1` : unable to read codec version, attempting download.").arg(versionFilePath);
|
||||||
|
return true;
|
||||||
|
} else if (!QString::compare(QTextStream(&versionFile).readAll(), mDownloadUrl, Qt::CaseInsensitive)) {
|
||||||
|
lInfo() << log().arg("Codec `%1` is installed and up to date.").arg(versionFilePath);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
71
Linphone/core/payload-type/DownloadablePayloadTypeCore.hpp
Normal file
71
Linphone/core/payload-type/DownloadablePayloadTypeCore.hpp
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-desktop
|
||||||
|
* (see https://www.linphone.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DOWNLOADABLE_PAYLOAD_TYPE_CORE_H_
|
||||||
|
#define DOWNLOADABLE_PAYLOAD_TYPE_CORE_H_
|
||||||
|
|
||||||
|
#include "PayloadTypeCore.hpp"
|
||||||
|
#include "tool/AbstractObject.hpp"
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <linphone++/linphone.hh>
|
||||||
|
|
||||||
|
class DownloadablePayloadTypeCore : public PayloadTypeCore {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE void downloadAndExtract(bool isUpdate = false);
|
||||||
|
bool shouldDownloadUpdate();
|
||||||
|
|
||||||
|
static QSharedPointer<DownloadablePayloadTypeCore> create(PayloadTypeCore::Family family,
|
||||||
|
const QString &mime,
|
||||||
|
const QString &encoderDescription,
|
||||||
|
const QString &downloadUrl,
|
||||||
|
const QString &installName,
|
||||||
|
const QString &checkSum);
|
||||||
|
|
||||||
|
DownloadablePayloadTypeCore(PayloadTypeCore::Family family,
|
||||||
|
const QString &mimeType,
|
||||||
|
const QString &encoderDescription,
|
||||||
|
const QString &downloadUrl,
|
||||||
|
const QString &installName,
|
||||||
|
const QString &checkSum);
|
||||||
|
|
||||||
|
~DownloadablePayloadTypeCore();
|
||||||
|
void setSelf(QSharedPointer<DownloadablePayloadTypeCore> me);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void success();
|
||||||
|
void downloadError();
|
||||||
|
void extractError();
|
||||||
|
void installedChanged();
|
||||||
|
void versionChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString mDownloadUrl;
|
||||||
|
QString mInstallName;
|
||||||
|
QString mCheckSum;
|
||||||
|
bool mInstalled;
|
||||||
|
QString mVersion;
|
||||||
|
|
||||||
|
DECLARE_ABSTRACT_OBJECT
|
||||||
|
};
|
||||||
|
Q_DECLARE_METATYPE(DownloadablePayloadTypeCore *)
|
||||||
|
#endif
|
||||||
|
|
@ -23,16 +23,16 @@
|
||||||
|
|
||||||
DEFINE_ABSTRACT_OBJECT(PayloadTypeCore)
|
DEFINE_ABSTRACT_OBJECT(PayloadTypeCore)
|
||||||
|
|
||||||
QSharedPointer<PayloadTypeCore> PayloadTypeCore::create(const std::shared_ptr<linphone::PayloadType> &payloadType,
|
QSharedPointer<PayloadTypeCore> PayloadTypeCore::create(Family family,
|
||||||
Family family) {
|
const std::shared_ptr<linphone::PayloadType> &payloadType) {
|
||||||
auto sharedPointer =
|
auto sharedPointer =
|
||||||
QSharedPointer<PayloadTypeCore>(new PayloadTypeCore(payloadType, family), &QObject::deleteLater);
|
QSharedPointer<PayloadTypeCore>(new PayloadTypeCore(family, payloadType), &QObject::deleteLater);
|
||||||
sharedPointer->setSelf(sharedPointer);
|
sharedPointer->setSelf(sharedPointer);
|
||||||
sharedPointer->moveToThread(App::getInstance()->thread());
|
sharedPointer->moveToThread(App::getInstance()->thread());
|
||||||
return sharedPointer;
|
return sharedPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
PayloadTypeCore::PayloadTypeCore(const std::shared_ptr<linphone::PayloadType> &payloadType, Family family)
|
PayloadTypeCore::PayloadTypeCore(Family family, const std::shared_ptr<linphone::PayloadType> &payloadType)
|
||||||
: QObject(nullptr) {
|
: QObject(nullptr) {
|
||||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||||
|
|
@ -42,6 +42,7 @@ PayloadTypeCore::PayloadTypeCore(const std::shared_ptr<linphone::PayloadType> &p
|
||||||
INIT_CORE_MEMBER(ClockRate, mPayloadTypeModel)
|
INIT_CORE_MEMBER(ClockRate, mPayloadTypeModel)
|
||||||
INIT_CORE_MEMBER(MimeType, mPayloadTypeModel)
|
INIT_CORE_MEMBER(MimeType, mPayloadTypeModel)
|
||||||
INIT_CORE_MEMBER(RecvFmtp, mPayloadTypeModel)
|
INIT_CORE_MEMBER(RecvFmtp, mPayloadTypeModel)
|
||||||
|
INIT_CORE_MEMBER(EncoderDescription, mPayloadTypeModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
PayloadTypeCore::~PayloadTypeCore() {
|
PayloadTypeCore::~PayloadTypeCore() {
|
||||||
|
|
@ -62,3 +63,7 @@ PayloadTypeCore::Family PayloadTypeCore::getFamily() {
|
||||||
QString PayloadTypeCore::getMimeType() {
|
QString PayloadTypeCore::getMimeType() {
|
||||||
return mMimeType;
|
return mMimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PayloadTypeCore::getDownloadable() {
|
||||||
|
return mDownloadable;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,25 +33,32 @@ class PayloadTypeCore : public QObject, public AbstractObject {
|
||||||
|
|
||||||
Q_ENUMS(Family)
|
Q_ENUMS(Family)
|
||||||
Q_PROPERTY(Family family MEMBER mFamily CONSTANT)
|
Q_PROPERTY(Family family MEMBER mFamily CONSTANT)
|
||||||
DECLARE_CORE_GETSET_MEMBER(bool, enabled, Enabled)
|
|
||||||
DECLARE_CORE_MEMBER(int, clockRate, ClockRate)
|
DECLARE_CORE_MEMBER(int, clockRate, ClockRate)
|
||||||
DECLARE_CORE_MEMBER(QString, mimeType, MimeType)
|
|
||||||
DECLARE_CORE_MEMBER(QString, recvFmtp, RecvFmtp)
|
DECLARE_CORE_MEMBER(QString, recvFmtp, RecvFmtp)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Family { None, Audio, Video, Text };
|
enum Family { None, Audio, Video, Text };
|
||||||
|
|
||||||
static QSharedPointer<PayloadTypeCore> create(const std::shared_ptr<linphone::PayloadType> &payloadType,
|
static QSharedPointer<PayloadTypeCore> create(Family family,
|
||||||
Family family);
|
const std::shared_ptr<linphone::PayloadType> &payloadType);
|
||||||
PayloadTypeCore(const std::shared_ptr<linphone::PayloadType> &payloadType, Family family);
|
|
||||||
|
PayloadTypeCore(Family family, const std::shared_ptr<linphone::PayloadType> &payloadType);
|
||||||
|
PayloadTypeCore() {};
|
||||||
~PayloadTypeCore();
|
~PayloadTypeCore();
|
||||||
|
|
||||||
void setSelf(QSharedPointer<PayloadTypeCore> me);
|
void setSelf(QSharedPointer<PayloadTypeCore> me);
|
||||||
Family getFamily();
|
Family getFamily();
|
||||||
|
bool getDownloadable();
|
||||||
QString getMimeType();
|
QString getMimeType();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
Family mFamily;
|
Family mFamily;
|
||||||
|
bool mDownloadable = false;
|
||||||
|
DECLARE_CORE_GETSET_MEMBER(bool, enabled, Enabled)
|
||||||
|
DECLARE_CORE_MEMBER(QString, mimeType, MimeType)
|
||||||
|
DECLARE_CORE_MEMBER(QString, encoderDescription, EncoderDescription)
|
||||||
|
|
||||||
|
private:
|
||||||
std::shared_ptr<PayloadTypeModel> mPayloadTypeModel;
|
std::shared_ptr<PayloadTypeModel> mPayloadTypeModel;
|
||||||
QSharedPointer<SafeConnection<PayloadTypeCore, PayloadTypeModel>> mPayloadTypeModelConnection;
|
QSharedPointer<SafeConnection<PayloadTypeCore, PayloadTypeModel>> mPayloadTypeModelConnection;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PayloadTypeList.hpp"
|
#include "PayloadTypeList.hpp"
|
||||||
|
#include "DownloadablePayloadTypeCore.hpp"
|
||||||
#include "PayloadTypeGui.hpp"
|
#include "PayloadTypeGui.hpp"
|
||||||
#include "core/App.hpp"
|
#include "core/App.hpp"
|
||||||
|
#include "core/path/Paths.hpp"
|
||||||
#include "model/object/VariantObject.hpp"
|
#include "model/object/VariantObject.hpp"
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <linphone++/linphone.hh>
|
#include <linphone++/linphone.hh>
|
||||||
|
|
@ -37,12 +39,12 @@ QSharedPointer<PayloadTypeList> PayloadTypeList::create() {
|
||||||
}
|
}
|
||||||
|
|
||||||
PayloadTypeList::PayloadTypeList(QObject *parent) : ListProxy(parent) {
|
PayloadTypeList::PayloadTypeList(QObject *parent) : ListProxy(parent) {
|
||||||
mustBeInMainThread(getClassName());
|
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||||
}
|
}
|
||||||
|
|
||||||
PayloadTypeList::~PayloadTypeList() {
|
PayloadTypeList::~PayloadTypeList() {
|
||||||
mustBeInMainThread("~" + getClassName());
|
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||||
mModelConnection = nullptr;
|
mModelConnection = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,21 +54,40 @@ void PayloadTypeList::setSelf(QSharedPointer<PayloadTypeList> me) {
|
||||||
mModelConnection->makeConnectToCore(&PayloadTypeList::lUpdate, [this]() {
|
mModelConnection->makeConnectToCore(&PayloadTypeList::lUpdate, [this]() {
|
||||||
mModelConnection->invokeToModel([this]() {
|
mModelConnection->invokeToModel([this]() {
|
||||||
QList<QSharedPointer<PayloadTypeCore>> *payloadTypes = new QList<QSharedPointer<PayloadTypeCore>>();
|
QList<QSharedPointer<PayloadTypeCore>> *payloadTypes = new QList<QSharedPointer<PayloadTypeCore>>();
|
||||||
mustBeInLinphoneThread(getClassName());
|
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||||
|
|
||||||
|
Utils::loadDownloadedCodecs();
|
||||||
|
|
||||||
|
// Audio
|
||||||
for (auto payloadType : CoreModel::getInstance()->getCore()->getAudioPayloadTypes()) {
|
for (auto payloadType : CoreModel::getInstance()->getCore()->getAudioPayloadTypes()) {
|
||||||
auto model = PayloadTypeCore::create(payloadType, PayloadTypeCore::Family::Audio);
|
auto core = PayloadTypeCore::create(PayloadTypeCore::Family::Audio, payloadType);
|
||||||
payloadTypes->push_back(model);
|
payloadTypes->push_back(core);
|
||||||
}
|
}
|
||||||
for (auto payloadType : CoreModel::getInstance()->getCore()->getVideoPayloadTypes()) {
|
|
||||||
auto model = PayloadTypeCore::create(payloadType, PayloadTypeCore::Family::Video);
|
// Video
|
||||||
payloadTypes->push_back(model);
|
auto videoCodecs = CoreModel::getInstance()->getCore()->getVideoPayloadTypes();
|
||||||
|
for (auto payloadType : videoCodecs) {
|
||||||
|
auto core = PayloadTypeCore::create(PayloadTypeCore::Family::Video, payloadType);
|
||||||
|
payloadTypes->push_back(core);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Downloadable Video
|
||||||
|
for (auto downloadableVideoCodec : Utils::getDownloadableVideoPayloadTypes()) {
|
||||||
|
if (find_if(videoCodecs.begin(), videoCodecs.end(),
|
||||||
|
[downloadableVideoCodec](const std::shared_ptr<linphone::PayloadType> &codec) {
|
||||||
|
return Utils::coreStringToAppString(codec->getMimeType()) ==
|
||||||
|
downloadableVideoCodec->getMimeType();
|
||||||
|
}) == videoCodecs.end())
|
||||||
|
payloadTypes->append(downloadableVideoCodec.dynamicCast<PayloadTypeCore>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text
|
||||||
for (auto payloadType : CoreModel::getInstance()->getCore()->getTextPayloadTypes()) {
|
for (auto payloadType : CoreModel::getInstance()->getCore()->getTextPayloadTypes()) {
|
||||||
auto model = PayloadTypeCore::create(payloadType, PayloadTypeCore::Family::Text);
|
auto core = PayloadTypeCore::create(PayloadTypeCore::Family::Text, payloadType);
|
||||||
payloadTypes->push_back(model);
|
payloadTypes->push_back(core);
|
||||||
}
|
}
|
||||||
mModelConnection->invokeToCore([this, payloadTypes]() {
|
mModelConnection->invokeToCore([this, payloadTypes]() {
|
||||||
mustBeInMainThread(getClassName());
|
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||||
resetData<PayloadTypeCore>(*payloadTypes);
|
resetData<PayloadTypeCore>(*payloadTypes);
|
||||||
delete payloadTypes;
|
delete payloadTypes;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ signals:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSharedPointer<SafeConnection<PayloadTypeList, CoreModel>> mModelConnection;
|
QSharedPointer<SafeConnection<PayloadTypeList, CoreModel>> mModelConnection;
|
||||||
|
|
||||||
DECLARE_ABSTRACT_OBJECT
|
DECLARE_ABSTRACT_OBJECT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,21 @@ void PayloadTypeProxy::setFamily(PayloadTypeCore::Family data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PayloadTypeProxy::isDownloadable() const {
|
||||||
|
return dynamic_cast<SortFilterList *>(sourceModel())->mDownloadable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PayloadTypeProxy::setDownloadable(bool data) {
|
||||||
|
auto list = dynamic_cast<SortFilterList *>(sourceModel());
|
||||||
|
if (list->mDownloadable != data) {
|
||||||
|
list->mDownloadable = data;
|
||||||
|
downloadableChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool PayloadTypeProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
bool PayloadTypeProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
||||||
auto payload = qobject_cast<PayloadTypeList *>(sourceModel())->getAt<PayloadTypeCore>(sourceRow);
|
auto payload = qobject_cast<PayloadTypeList *>(sourceModel())->getAt<PayloadTypeCore>(sourceRow);
|
||||||
return payload->getFamily() == mFamily;
|
return payload->getFamily() == mFamily && payload->getDownloadable() == mDownloadable;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PayloadTypeProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
|
bool PayloadTypeProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
|
||||||
|
|
@ -55,3 +67,7 @@ bool PayloadTypeProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, c
|
||||||
|
|
||||||
return l->getMimeType() < r->getMimeType();
|
return l->getMimeType() < r->getMimeType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PayloadTypeProxy::reload() {
|
||||||
|
emit mPayloadTypeList->lUpdate();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,18 +31,24 @@ class PayloadTypeProxy : public LimitProxy, public AbstractObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(PayloadTypeCore::Family family READ getFamily WRITE setFamily NOTIFY familyChanged)
|
Q_PROPERTY(PayloadTypeCore::Family family READ getFamily WRITE setFamily NOTIFY familyChanged)
|
||||||
|
Q_PROPERTY(bool downloadable READ isDownloadable WRITE setDownloadable NOTIFY downloadableChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DECLARE_SORTFILTER_CLASS(PayloadTypeCore::Family mFamily;)
|
DECLARE_SORTFILTER_CLASS(PayloadTypeCore::Family mFamily; bool mDownloadable;)
|
||||||
|
|
||||||
|
Q_INVOKABLE void reload();
|
||||||
|
|
||||||
PayloadTypeProxy(QObject *parent = Q_NULLPTR);
|
PayloadTypeProxy(QObject *parent = Q_NULLPTR);
|
||||||
~PayloadTypeProxy();
|
~PayloadTypeProxy();
|
||||||
|
|
||||||
PayloadTypeCore::Family getFamily() const;
|
PayloadTypeCore::Family getFamily() const;
|
||||||
void setFamily(PayloadTypeCore::Family data);
|
void setFamily(PayloadTypeCore::Family data);
|
||||||
|
bool isDownloadable() const;
|
||||||
|
void setDownloadable(bool data);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void familyChanged();
|
void familyChanged();
|
||||||
|
void downloadableChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QSharedPointer<PayloadTypeList> mPayloadTypeList;
|
QSharedPointer<PayloadTypeList> mPayloadTypeList;
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ SettingsCore::SettingsCore(QObject *parent) : QObject(parent) {
|
||||||
INIT_CORE_MEMBER(SyncLdapContacts, settingsModel)
|
INIT_CORE_MEMBER(SyncLdapContacts, settingsModel)
|
||||||
INIT_CORE_MEMBER(Ipv6Enabled, settingsModel)
|
INIT_CORE_MEMBER(Ipv6Enabled, settingsModel)
|
||||||
INIT_CORE_MEMBER(ConfigLocale, settingsModel)
|
INIT_CORE_MEMBER(ConfigLocale, settingsModel)
|
||||||
|
INIT_CORE_MEMBER(DownloadFolder, settingsModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsCore::~SettingsCore() {
|
SettingsCore::~SettingsCore() {
|
||||||
|
|
@ -348,6 +349,8 @@ void SettingsCore::setSelf(QSharedPointer<SettingsCore> me) {
|
||||||
Ipv6Enabled)
|
Ipv6Enabled)
|
||||||
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QString,
|
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QString,
|
||||||
configLocale, ConfigLocale)
|
configLocale, ConfigLocale)
|
||||||
|
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QString,
|
||||||
|
downloadFolder, DownloadFolder)
|
||||||
|
|
||||||
auto coreModelConnection = QSharedPointer<SafeConnection<SettingsCore, CoreModel>>(
|
auto coreModelConnection = QSharedPointer<SafeConnection<SettingsCore, CoreModel>>(
|
||||||
new SafeConnection<SettingsCore, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater);
|
new SafeConnection<SettingsCore, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater);
|
||||||
|
|
@ -523,3 +526,9 @@ bool SettingsCore::getSyncLdapContacts() const {
|
||||||
QString SettingsCore::getConfigLocale() const {
|
QString SettingsCore::getConfigLocale() const {
|
||||||
return mConfigLocale;
|
return mConfigLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString SettingsCore::getDownloadFolder() const {
|
||||||
|
auto path = mDownloadFolder;
|
||||||
|
if (mDownloadFolder.isEmpty()) path = Paths::getDownloadDirPath();
|
||||||
|
return QDir::cleanPath(path) + QDir::separator();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,7 @@ public:
|
||||||
DECLARE_CORE_GETSET_MEMBER(QVariantList, audioCodecs, AudioCodecs)
|
DECLARE_CORE_GETSET_MEMBER(QVariantList, audioCodecs, AudioCodecs)
|
||||||
DECLARE_CORE_GETSET_MEMBER(QVariantList, videoCodecs, VideoCodecs)
|
DECLARE_CORE_GETSET_MEMBER(QVariantList, videoCodecs, VideoCodecs)
|
||||||
DECLARE_CORE_GETSET(QString, configLocale, ConfigLocale)
|
DECLARE_CORE_GETSET(QString, configLocale, ConfigLocale)
|
||||||
|
DECLARE_CORE_GETSET(QString, downloadFolder, DownloadFolder)
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,3 +36,4 @@ DEFINE_GETSET_ENABLE(PayloadTypeModel, enabled, Enabled, mPayloadType)
|
||||||
DEFINE_GET(PayloadTypeModel, int, ClockRate, mPayloadType)
|
DEFINE_GET(PayloadTypeModel, int, ClockRate, mPayloadType)
|
||||||
DEFINE_GET_STRING(PayloadTypeModel, MimeType, mPayloadType)
|
DEFINE_GET_STRING(PayloadTypeModel, MimeType, mPayloadType)
|
||||||
DEFINE_GET_STRING(PayloadTypeModel, RecvFmtp, mPayloadType)
|
DEFINE_GET_STRING(PayloadTypeModel, RecvFmtp, mPayloadType)
|
||||||
|
DEFINE_GET_STRING(PayloadTypeModel, EncoderDescription, mPayloadType)
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ public:
|
||||||
int getClockRate() const;
|
int getClockRate() const;
|
||||||
QString getMimeType() const;
|
QString getMimeType() const;
|
||||||
QString getRecvFmtp() const;
|
QString getRecvFmtp() const;
|
||||||
|
QString getEncoderDescription() const;
|
||||||
|
|
||||||
DECLARE_GETSET(bool, enabled, Enabled)
|
DECLARE_GETSET(bool, enabled, Enabled)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -571,6 +571,7 @@ void SettingsModel::notifyConfigReady(){
|
||||||
DEFINE_NOTIFY_CONFIG_READY(exitOnClose, ExitOnClose)
|
DEFINE_NOTIFY_CONFIG_READY(exitOnClose, ExitOnClose)
|
||||||
DEFINE_NOTIFY_CONFIG_READY(syncLdapContacts, SyncLdapContacts)
|
DEFINE_NOTIFY_CONFIG_READY(syncLdapContacts, SyncLdapContacts)
|
||||||
DEFINE_NOTIFY_CONFIG_READY(configLocale, ConfigLocale)
|
DEFINE_NOTIFY_CONFIG_READY(configLocale, ConfigLocale)
|
||||||
|
DEFINE_NOTIFY_CONFIG_READY(downloadFolder, DownloadFolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_GETSET_CONFIG(SettingsModel, bool, Bool, disableChatFeature, DisableChatFeature, "disable_chat_feature", true)
|
DEFINE_GETSET_CONFIG(SettingsModel, bool, Bool, disableChatFeature, DisableChatFeature, "disable_chat_feature", true)
|
||||||
|
|
@ -673,4 +674,9 @@ DEFINE_GETSET_CONFIG_STRING(SettingsModel,
|
||||||
ConfigLocale,
|
ConfigLocale,
|
||||||
"locale",
|
"locale",
|
||||||
"")
|
"")
|
||||||
|
DEFINE_GETSET_CONFIG_STRING(SettingsModel,
|
||||||
|
downloadFolder,
|
||||||
|
DownloadFolder,
|
||||||
|
"download_folder",
|
||||||
|
"")
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,7 @@ public:
|
||||||
DECLARE_GETSET(bool, syncLdapContacts, SyncLdapContacts)
|
DECLARE_GETSET(bool, syncLdapContacts, SyncLdapContacts)
|
||||||
DECLARE_GETSET(bool, ipv6Enabled, Ipv6Enabled)
|
DECLARE_GETSET(bool, ipv6Enabled, Ipv6Enabled)
|
||||||
DECLARE_GETSET(QString, configLocale, ConfigLocale)
|
DECLARE_GETSET(QString, configLocale, ConfigLocale)
|
||||||
|
DECLARE_GETSET(QString, downloadFolder, DownloadFolder)
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,10 @@ list(APPEND _LINPHONEAPP_SOURCES
|
||||||
|
|
||||||
tool/request/RequestDialog.cpp
|
tool/request/RequestDialog.cpp
|
||||||
tool/request/AuthenticationDialog.cpp
|
tool/request/AuthenticationDialog.cpp
|
||||||
|
|
||||||
|
tool/file/FileDownloader.cpp
|
||||||
|
tool/file/FileExtractor.cpp
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
|
|
||||||
|
|
@ -159,3 +159,4 @@ constexpr char Constants::LinphoneBZip2_exe[];
|
||||||
constexpr char Constants::LinphoneBZip2_dll[];
|
constexpr char Constants::LinphoneBZip2_dll[];
|
||||||
constexpr char Constants::DefaultRlsUri[];
|
constexpr char Constants::DefaultRlsUri[];
|
||||||
constexpr char Constants::DefaultLogsEmail[];
|
constexpr char Constants::DefaultLogsEmail[];
|
||||||
|
constexpr char Constants::DownloadDefaultFileName[];
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,8 @@ public:
|
||||||
// 4 = RTP bundle mode
|
// 4 = RTP bundle mode
|
||||||
// 5 = Video Conference URI
|
// 5 = Video Conference URI
|
||||||
// 6 = Publish expires
|
// 6 = Publish expires
|
||||||
|
static constexpr char DownloadDefaultFileName[] = "download";
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
// CISCO
|
// CISCO
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "core/conference/ConferenceInfoGui.hpp"
|
#include "core/conference/ConferenceInfoGui.hpp"
|
||||||
#include "core/friend/FriendGui.hpp"
|
#include "core/friend/FriendGui.hpp"
|
||||||
#include "core/path/Paths.hpp"
|
#include "core/path/Paths.hpp"
|
||||||
|
#include "core/payload-type/DownloadablePayloadTypeCore.hpp"
|
||||||
#include "model/object/VariantObject.hpp"
|
#include "model/object/VariantObject.hpp"
|
||||||
#include "model/tool/ToolModel.hpp"
|
#include "model/tool/ToolModel.hpp"
|
||||||
#include "tool/providers/AvatarProvider.hpp"
|
#include "tool/providers/AvatarProvider.hpp"
|
||||||
|
|
@ -33,13 +34,18 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
|
#include <QCryptographicHash>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <QDirIterator>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
|
#include <QLibrary>
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
DEFINE_ABSTRACT_OBJECT(Utils)
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
char *Utils::rstrstr(const char *a, const char *b) {
|
char *Utils::rstrstr(const char *a, const char *b) {
|
||||||
|
|
@ -1403,3 +1409,77 @@ QString Utils::boldTextPart(const QString &text, const QString ®ex) {
|
||||||
if (splittedText.size() > 0) result.append(splittedText[splittedText.size() - 1]);
|
if (splittedText.size() > 0) result.append(splittedText[splittedText.size() - 1]);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Utils::getFileChecksum(const QString &filePath) {
|
||||||
|
QFile file(filePath);
|
||||||
|
if (file.open(QFile::ReadOnly)) {
|
||||||
|
QCryptographicHash hash(QCryptographicHash::Sha256);
|
||||||
|
if (hash.addData(&file)) {
|
||||||
|
return hash.result().toHex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Codecs download
|
||||||
|
|
||||||
|
QList<QSharedPointer<DownloadablePayloadTypeCore>> Utils::getDownloadableVideoPayloadTypes() {
|
||||||
|
QList<QSharedPointer<DownloadablePayloadTypeCore>> payloadTypes;
|
||||||
|
#if defined(Q_OS_LINUX) || defined(Q_OS_WIN)
|
||||||
|
auto ciscoH264 = DownloadablePayloadTypeCore::create(PayloadTypeCore::Family::Video, "H264",
|
||||||
|
Constants::H264Description, Constants::PluginUrlH264,
|
||||||
|
Constants::H264InstallName, Constants::PluginH264Check);
|
||||||
|
payloadTypes.push_back(ciscoH264);
|
||||||
|
#endif
|
||||||
|
return payloadTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::checkDownloadedCodecsUpdates() {
|
||||||
|
for (auto codec : getDownloadableVideoPayloadTypes()) {
|
||||||
|
if (codec->shouldDownloadUpdate()) codec->downloadAndExtract(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load downloaded codecs like OpenH264 (needs to be after core is created and has loaded its plugins, as
|
||||||
|
// reloadMsPlugins modifies plugin path for the factory)
|
||||||
|
void Utils::loadDownloadedCodecs() {
|
||||||
|
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
|
||||||
|
#if defined(Q_OS_LINUX) || defined(Q_OS_WIN)
|
||||||
|
QDirIterator it(Paths::getCodecsDirPath());
|
||||||
|
while (it.hasNext()) {
|
||||||
|
QFileInfo info(it.next());
|
||||||
|
const QString filename(info.fileName());
|
||||||
|
if (QLibrary::isLibrary(filename)) {
|
||||||
|
qInfo() << QStringLiteral("Loading `%1` symbols...").arg(filename);
|
||||||
|
if (!QLibrary(info.filePath()).load()) // lib.load())
|
||||||
|
qWarning() << QStringLiteral("Failed to load `%1` symbols.").arg(filename);
|
||||||
|
else qInfo() << QStringLiteral("Loaded `%1` symbols...").arg(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CoreModel::getInstance()->getCore()->reloadMsPlugins("");
|
||||||
|
#endif // if defined(Q_OS_LINUX) || defined(Q_OS_WIN)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes .in suffix from downloaded updates.
|
||||||
|
// Updates are downloaded with .in suffix as they can't overwrite already loaded plugin
|
||||||
|
// they are loaded at next app startup.
|
||||||
|
|
||||||
|
void Utils::updateCodecs() {
|
||||||
|
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
|
||||||
|
#if defined(Q_OS_LINUX) || defined(Q_OS_WIN)
|
||||||
|
static const QString codecSuffix = QStringLiteral(".%1").arg(Constants::LibraryExtension);
|
||||||
|
|
||||||
|
QDirIterator it(Paths::getCodecsDirPath());
|
||||||
|
while (it.hasNext()) {
|
||||||
|
QFileInfo info(it.next());
|
||||||
|
if (info.suffix() == QLatin1String("in")) {
|
||||||
|
QString codecName = info.completeBaseName();
|
||||||
|
if (codecName.endsWith(codecSuffix)) {
|
||||||
|
QString codecPath = info.dir().path() + QDir::separator() + codecName;
|
||||||
|
QFile::remove(codecPath);
|
||||||
|
QFile::rename(info.filePath(), codecPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // if defined(Q_OS_LINUX) || defined(Q_OS_WIN)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include "Constants.hpp"
|
#include "Constants.hpp"
|
||||||
|
#include "tool/AbstractObject.hpp"
|
||||||
#include "tool/LinphoneEnums.hpp"
|
#include "tool/LinphoneEnums.hpp"
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -47,8 +48,9 @@ class QQuickWindow;
|
||||||
class VariantObject;
|
class VariantObject;
|
||||||
class CallGui;
|
class CallGui;
|
||||||
class ConferenceInfoGui;
|
class ConferenceInfoGui;
|
||||||
|
class DownloadablePayloadTypeCore;
|
||||||
|
|
||||||
class Utils : public QObject {
|
class Utils : public QObject, public AbstractObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Utils(QObject *parent = nullptr) : QObject(parent) {
|
Utils(QObject *parent = nullptr) : QObject(parent) {
|
||||||
|
|
@ -131,10 +133,15 @@ public:
|
||||||
Q_INVOKABLE void playDtmf(const QString &dtmf);
|
Q_INVOKABLE void playDtmf(const QString &dtmf);
|
||||||
Q_INVOKABLE bool isInteger(const QString &text);
|
Q_INVOKABLE bool isInteger(const QString &text);
|
||||||
Q_INVOKABLE QString boldTextPart(const QString &text, const QString ®ex);
|
Q_INVOKABLE QString boldTextPart(const QString &text, const QString ®ex);
|
||||||
|
Q_INVOKABLE static QString getFileChecksum(const QString &filePath);
|
||||||
|
|
||||||
static QString getApplicationProduct();
|
static QString getApplicationProduct();
|
||||||
static QString getOsProduct();
|
static QString getOsProduct();
|
||||||
static QString computeUserAgent();
|
static QString computeUserAgent();
|
||||||
|
static QList<QSharedPointer<DownloadablePayloadTypeCore>> getDownloadableVideoPayloadTypes();
|
||||||
|
static void checkDownloadedCodecsUpdates();
|
||||||
|
static void loadDownloadedCodecs();
|
||||||
|
static void updateCodecs();
|
||||||
|
|
||||||
static inline QString coreStringToAppString(const std::string &str) {
|
static inline QString coreStringToAppString(const std::string &str) {
|
||||||
if (Constants::LinphoneLocaleEncoding == QString("UTF-8")) return QString::fromStdString(str);
|
if (Constants::LinphoneLocaleEncoding == QString("UTF-8")) return QString::fromStdString(str);
|
||||||
|
|
@ -165,6 +172,9 @@ public:
|
||||||
|
|
||||||
return (volume - VuMin) / (VuMax - VuMin);
|
return (volume - VuMin) / (VuMax - VuMin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DECLARE_ABSTRACT_OBJECT
|
||||||
};
|
};
|
||||||
|
|
||||||
#define lDebug() qDebug().noquote()
|
#define lDebug() qDebug().noquote()
|
||||||
|
|
|
||||||
290
Linphone/tool/file/FileDownloader.cpp
Normal file
290
Linphone/tool/file/FileDownloader.cpp
Normal file
|
|
@ -0,0 +1,290 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-desktop
|
||||||
|
* (see https://www.linphone.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "core/App.hpp"
|
||||||
|
#include "core/path/Paths.hpp"
|
||||||
|
#include "tool/Utils.hpp"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QTest>
|
||||||
|
|
||||||
|
#include "FileDownloader.hpp"
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
static QString getDownloadFilePath(const QString &folder, const QUrl &url, const bool &overwrite) {
|
||||||
|
QString defaultFileName = QString(Constants::DownloadDefaultFileName);
|
||||||
|
QFileInfo fileInfo(url.path());
|
||||||
|
QString fileName = fileInfo.fileName();
|
||||||
|
if (fileName.isEmpty()) fileName = defaultFileName;
|
||||||
|
|
||||||
|
fileName.prepend(folder);
|
||||||
|
if (overwrite && QFile::exists(fileName)) QFile::remove(fileName);
|
||||||
|
if (!QFile::exists(fileName)) return fileName;
|
||||||
|
|
||||||
|
// Already exists, don't overwrite.
|
||||||
|
QString baseName = fileInfo.completeBaseName();
|
||||||
|
if (baseName.isEmpty()) baseName = defaultFileName;
|
||||||
|
|
||||||
|
QString suffix = fileInfo.suffix();
|
||||||
|
if (!suffix.isEmpty()) suffix.prepend(".");
|
||||||
|
|
||||||
|
for (int i = 1; true; ++i) {
|
||||||
|
fileName = folder + baseName + "(" + QString::number(i) + ")" + suffix;
|
||||||
|
if (!QFile::exists(fileName)) break;
|
||||||
|
}
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isHttpRedirect(QNetworkReply *reply) {
|
||||||
|
Q_CHECK_PTR(reply);
|
||||||
|
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
return statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 305 || statusCode == 307 ||
|
||||||
|
statusCode == 308;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void FileDownloader::download() {
|
||||||
|
if (mDownloading) {
|
||||||
|
qWarning() << "Unable to download file. Already downloading!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setDownloading(true);
|
||||||
|
|
||||||
|
QNetworkRequest request(mUrl);
|
||||||
|
mNetworkReply = mManager.get(request);
|
||||||
|
|
||||||
|
QNetworkReply *data = mNetworkReply.data();
|
||||||
|
|
||||||
|
QObject::connect(data, &QNetworkReply::readyRead, this, &FileDownloader::handleReadyData);
|
||||||
|
QObject::connect(data, &QNetworkReply::finished, this, &FileDownloader::handleDownloadFinished);
|
||||||
|
QObject::connect(data, &QNetworkReply::errorOccurred, this, &FileDownloader::handleError);
|
||||||
|
QObject::connect(data, &QNetworkReply::downloadProgress, this, &FileDownloader::handleDownloadProgress);
|
||||||
|
|
||||||
|
#if QT_CONFIG(ssl)
|
||||||
|
QObject::connect(data, &QNetworkReply::sslErrors, this, &FileDownloader::handleSslErrors);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (mDownloadFolder.isEmpty()) {
|
||||||
|
mDownloadFolder = App::getInstance()->getSettings()->getDownloadFolder();
|
||||||
|
emit downloadFolderChanged(mDownloadFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(!mDestinationFile.isOpen());
|
||||||
|
mDestinationFile.setFileName(
|
||||||
|
getDownloadFilePath(QDir::cleanPath(mDownloadFolder) + QDir::separator(), mUrl, mOverwriteFile));
|
||||||
|
if (!mDestinationFile.open(QIODevice::WriteOnly)) emitOutputError();
|
||||||
|
else {
|
||||||
|
mTimeoutReadBytes = 0;
|
||||||
|
mTimeout.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileDownloader::remove() {
|
||||||
|
return mDestinationFile.exists() && !mDestinationFile.isOpen() && mDestinationFile.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::emitOutputError() {
|
||||||
|
qWarning() << QStringLiteral("Could not write into `%1` (%2).")
|
||||||
|
.arg(mDestinationFile.fileName())
|
||||||
|
.arg(mDestinationFile.errorString());
|
||||||
|
mNetworkReply->abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::cleanDownloadEnd() {
|
||||||
|
mTimeout.stop();
|
||||||
|
mNetworkReply->deleteLater();
|
||||||
|
setDownloading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::handleReadyData() {
|
||||||
|
QByteArray data = mNetworkReply->readAll();
|
||||||
|
if (mDestinationFile.write(data) == -1) emitOutputError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::handleDownloadFinished() {
|
||||||
|
if (mNetworkReply->error() != QNetworkReply::NoError) return;
|
||||||
|
|
||||||
|
if (isHttpRedirect(mNetworkReply)) {
|
||||||
|
qWarning() << QStringLiteral("Request was redirected.");
|
||||||
|
mDestinationFile.remove();
|
||||||
|
cleanDownloadEnd();
|
||||||
|
emit downloadFailed();
|
||||||
|
} else {
|
||||||
|
qInfo() << QStringLiteral("Download of %1 finished to %2").arg(mUrl.toString(), mDestinationFile.fileName());
|
||||||
|
mDestinationFile.close();
|
||||||
|
cleanDownloadEnd();
|
||||||
|
QString fileChecksum = Utils::getFileChecksum(mDestinationFile.fileName());
|
||||||
|
if (mCheckSum.isEmpty() || fileChecksum == mCheckSum) emit downloadFinished(mDestinationFile.fileName());
|
||||||
|
else {
|
||||||
|
qCritical() << "File cannot be downloaded : Bad checksum " << fileChecksum;
|
||||||
|
mDestinationFile.remove();
|
||||||
|
emit downloadFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::handleError(QNetworkReply::NetworkError code) {
|
||||||
|
if (code != QNetworkReply::OperationCanceledError)
|
||||||
|
qWarning()
|
||||||
|
<< QStringLiteral("Download of %1 failed: %2").arg(mUrl.toString()).arg(mNetworkReply->errorString());
|
||||||
|
mDestinationFile.remove();
|
||||||
|
|
||||||
|
cleanDownloadEnd();
|
||||||
|
|
||||||
|
emit downloadFailed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::handleSslErrors(const QList<QSslError> &sslErrors) {
|
||||||
|
#if QT_CONFIG(ssl)
|
||||||
|
for (const QSslError &error : sslErrors)
|
||||||
|
qWarning() << QStringLiteral("SSL error: %1").arg(error.errorString());
|
||||||
|
#else
|
||||||
|
Q_UNUSED(sslErrors);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::handleTimeout() {
|
||||||
|
if (mReadBytes == mTimeoutReadBytes) {
|
||||||
|
qWarning() << QStringLiteral("Download of %1 failed: timeout.").arg(mUrl.toString());
|
||||||
|
mNetworkReply->abort();
|
||||||
|
} else mTimeoutReadBytes = mReadBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::handleDownloadProgress(qint64 readBytes, qint64 totalBytes) {
|
||||||
|
setReadBytes(readBytes);
|
||||||
|
setTotalBytes(totalBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
QUrl FileDownloader::getUrl() const {
|
||||||
|
return mUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::setUrl(const QUrl &url) {
|
||||||
|
if (mDownloading) {
|
||||||
|
qWarning() << QStringLiteral("Unable to set url, a file is downloading.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUrl != url) {
|
||||||
|
mUrl = url;
|
||||||
|
if (!QSslSocket::supportsSsl() && mUrl.scheme() == "https") {
|
||||||
|
qWarning() << "Https has been requested but SSL is not supported. Fallback to http. Install manually "
|
||||||
|
"OpenSSL libraries in your PATH.";
|
||||||
|
mUrl.setScheme("http");
|
||||||
|
}
|
||||||
|
emit urlChanged(mUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileDownloader::getDownloadFolder() const {
|
||||||
|
return mDownloadFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::setDownloadFolder(const QString &downloadFolder) {
|
||||||
|
if (mDownloading) {
|
||||||
|
qWarning() << QStringLiteral("Unable to set download folder, a file is downloading.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDownloadFolder != downloadFolder) {
|
||||||
|
mDownloadFolder = downloadFolder;
|
||||||
|
emit downloadFolderChanged(mDownloadFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileDownloader::getDestinationFileName() const {
|
||||||
|
return mDestinationFile.fileName();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::setOverwriteFile(const bool &overwrite) {
|
||||||
|
mOverwriteFile = overwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
FileDownloader::synchronousDownload(const QUrl &url, const QString &destinationFolder, const bool &overwriteFile) {
|
||||||
|
QString filePath;
|
||||||
|
FileDownloader downloader;
|
||||||
|
if (url.isRelative()) qWarning() << "FileDownloader: The specified URL is not valid";
|
||||||
|
else {
|
||||||
|
bool isOver = false;
|
||||||
|
bool *pIsOver = &isOver;
|
||||||
|
downloader.setUrl(url);
|
||||||
|
downloader.setOverwriteFile(overwriteFile);
|
||||||
|
downloader.setDownloadFolder(destinationFolder);
|
||||||
|
connect(&downloader, &FileDownloader::downloadFinished, [pIsOver]() mutable { *pIsOver = true; });
|
||||||
|
connect(&downloader, &FileDownloader::downloadFailed, [pIsOver]() mutable { *pIsOver = true; });
|
||||||
|
downloader.download();
|
||||||
|
if (QTest::qWaitFor([&]() { return isOver; }, DefaultTimeout)) {
|
||||||
|
filePath = downloader.getDestinationFileName();
|
||||||
|
if (!QFile::exists(filePath)) {
|
||||||
|
filePath = "";
|
||||||
|
qWarning() << "FileDownloader: Cannot download the specified file";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileDownloader::getChecksum() const {
|
||||||
|
return mCheckSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::setChecksum(const QString &code) {
|
||||||
|
if (mCheckSum != code) {
|
||||||
|
mCheckSum = code;
|
||||||
|
emit checksumChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 FileDownloader::getReadBytes() const {
|
||||||
|
return mReadBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::setReadBytes(qint64 readBytes) {
|
||||||
|
if (mReadBytes != readBytes) {
|
||||||
|
mReadBytes = readBytes;
|
||||||
|
emit readBytesChanged(readBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 FileDownloader::getTotalBytes() const {
|
||||||
|
return mTotalBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::setTotalBytes(qint64 totalBytes) {
|
||||||
|
if (mTotalBytes != totalBytes) {
|
||||||
|
mTotalBytes = totalBytes;
|
||||||
|
emit totalBytesChanged(totalBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileDownloader::getDownloading() const {
|
||||||
|
return mDownloading;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDownloader::setDownloading(bool downloading) {
|
||||||
|
if (mDownloading != downloading) {
|
||||||
|
mDownloading = downloading;
|
||||||
|
emit downloadingChanged(downloading);
|
||||||
|
}
|
||||||
|
}
|
||||||
126
Linphone/tool/file/FileDownloader.hpp
Normal file
126
Linphone/tool/file/FileDownloader.hpp
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-desktop
|
||||||
|
* (see https://www.linphone.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FILE_DOWNLOADER_H_
|
||||||
|
#define FILE_DOWNLOADER_H_
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QtNetwork>
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
class QSslError;
|
||||||
|
|
||||||
|
class FileDownloader : public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
// TODO: Add an error property to use in UI.
|
||||||
|
|
||||||
|
Q_PROPERTY(QUrl url READ getUrl WRITE setUrl NOTIFY urlChanged);
|
||||||
|
Q_PROPERTY(QString downloadFolder READ getDownloadFolder WRITE setDownloadFolder NOTIFY downloadFolderChanged);
|
||||||
|
Q_PROPERTY(qint64 readBytes READ getReadBytes NOTIFY readBytesChanged);
|
||||||
|
Q_PROPERTY(qint64 totalBytes READ getTotalBytes NOTIFY totalBytesChanged);
|
||||||
|
Q_PROPERTY(bool downloading READ getDownloading NOTIFY downloadingChanged);
|
||||||
|
Q_PROPERTY(QString checksum READ getChecksum WRITE setChecksum NOTIFY checksumChanged);
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileDownloader(QObject *parent = Q_NULLPTR) : QObject(parent) {
|
||||||
|
// See: https://bugreports.qt.io/browse/QTBUG-57390
|
||||||
|
mTimeout.setInterval(DefaultTimeout);
|
||||||
|
QObject::connect(&mTimeout, &QTimer::timeout, this, &FileDownloader::handleTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
~FileDownloader() {
|
||||||
|
if (mNetworkReply) mNetworkReply->abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_INVOKABLE void download();
|
||||||
|
Q_INVOKABLE bool remove();
|
||||||
|
|
||||||
|
QUrl getUrl() const;
|
||||||
|
void setUrl(const QUrl &url);
|
||||||
|
|
||||||
|
QString getDownloadFolder() const;
|
||||||
|
void setDownloadFolder(const QString &downloadFolder);
|
||||||
|
|
||||||
|
QString getDestinationFileName() const;
|
||||||
|
|
||||||
|
void setOverwriteFile(const bool &overwrite);
|
||||||
|
static QString
|
||||||
|
synchronousDownload(const QUrl &url,
|
||||||
|
const QString &destinationFolder,
|
||||||
|
const bool &overwriteFile); // Return the filpath. Empty if nof file could be downloaded
|
||||||
|
|
||||||
|
QString getChecksum() const;
|
||||||
|
void setChecksum(const QString &code);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void urlChanged(const QUrl &url);
|
||||||
|
void downloadFolderChanged(const QString &downloadFolder);
|
||||||
|
void readBytesChanged(qint64 readBytes);
|
||||||
|
void totalBytesChanged(qint64 totalBytes);
|
||||||
|
void downloadingChanged(bool downloading);
|
||||||
|
void downloadFinished(const QString &filePath);
|
||||||
|
void downloadFailed();
|
||||||
|
void checksumChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
qint64 getReadBytes() const;
|
||||||
|
void setReadBytes(qint64 readBytes);
|
||||||
|
|
||||||
|
qint64 getTotalBytes() const;
|
||||||
|
void setTotalBytes(qint64 totalBytes);
|
||||||
|
|
||||||
|
bool getDownloading() const;
|
||||||
|
void setDownloading(bool downloading);
|
||||||
|
|
||||||
|
void emitOutputError();
|
||||||
|
|
||||||
|
void cleanDownloadEnd();
|
||||||
|
|
||||||
|
void handleReadyData();
|
||||||
|
void handleDownloadFinished();
|
||||||
|
|
||||||
|
void handleError(QNetworkReply::NetworkError code);
|
||||||
|
void handleSslErrors(const QList<QSslError> &errors);
|
||||||
|
void handleTimeout();
|
||||||
|
void handleDownloadProgress(qint64 readBytes, qint64 totalBytes);
|
||||||
|
|
||||||
|
QUrl mUrl;
|
||||||
|
QString mDownloadFolder;
|
||||||
|
QFile mDestinationFile;
|
||||||
|
QString mCheckSum;
|
||||||
|
|
||||||
|
qint64 mReadBytes = 0;
|
||||||
|
qint64 mTotalBytes = 0;
|
||||||
|
bool mDownloading = false;
|
||||||
|
bool mOverwriteFile = false;
|
||||||
|
|
||||||
|
QPointer<QNetworkReply> mNetworkReply;
|
||||||
|
QNetworkAccessManager mManager;
|
||||||
|
|
||||||
|
qint64 mTimeoutReadBytes;
|
||||||
|
QTimer mTimeout;
|
||||||
|
|
||||||
|
static constexpr int DefaultTimeout = 5000;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILE_DOWNLOADER_H_
|
||||||
237
Linphone/tool/file/FileExtractor.cpp
Normal file
237
Linphone/tool/file/FileExtractor.cpp
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-desktop
|
||||||
|
* (see https://www.linphone.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "FileDownloader.hpp"
|
||||||
|
#include "FileExtractor.hpp"
|
||||||
|
#include "core/path/Paths.hpp"
|
||||||
|
#include "tool/Constants.hpp"
|
||||||
|
#include "tool/Utils.hpp"
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
FileExtractor::FileExtractor(QObject *parent) : QObject(parent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
FileExtractor::~FileExtractor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileExtractor::extract() {
|
||||||
|
if (mExtracting) {
|
||||||
|
qWarning() << "Unable to extract file. Already extracting!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setExtracting(true);
|
||||||
|
QFileInfo fileInfo(mFile);
|
||||||
|
if (!fileInfo.isReadable()) {
|
||||||
|
emitExtractFailed(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDestinationFile = QDir::cleanPath(mExtractFolder) + QDir::separator() +
|
||||||
|
(mExtractName.isEmpty() ? fileInfo.completeBaseName() : mExtractName);
|
||||||
|
if (QFile::exists(mDestinationFile) && !QFile::remove(mDestinationFile)) {
|
||||||
|
emitOutputError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mTimer == nullptr) {
|
||||||
|
mTimer = new QTimer(this);
|
||||||
|
QObject::connect(mTimer, &QTimer::timeout, this, &FileExtractor::handleExtraction);
|
||||||
|
}
|
||||||
|
#ifdef WIN32
|
||||||
|
// Test the presence of bzip2 in the system
|
||||||
|
QProcess process;
|
||||||
|
process.closeReadChannel(QProcess::StandardOutput);
|
||||||
|
process.closeReadChannel(QProcess::StandardError);
|
||||||
|
process.start("bzip2.exe", QStringList("--help"));
|
||||||
|
// int result = QProcess::execute("bzip2.exe", QStringList("--help"));
|
||||||
|
if (process.error() != QProcess::FailedToStart ||
|
||||||
|
QProcess::execute(Paths::getToolsDirPath() + "\\bzip2.exe", QStringList()) != -2) {
|
||||||
|
mTimer->start();
|
||||||
|
} else { // Download bzip2
|
||||||
|
qWarning() << "bzip2 was not found. Downloading it.";
|
||||||
|
QTimer *timer = mTimer;
|
||||||
|
FileDownloader *fileDownloader = new FileDownloader();
|
||||||
|
int downloadStep = 0;
|
||||||
|
fileDownloader->setUrl(QUrl(Constants::LinphoneBZip2_exe));
|
||||||
|
fileDownloader->setDownloadFolder(Paths::getToolsDirPath());
|
||||||
|
QObject::connect(fileDownloader, &FileDownloader::totalBytesChanged, this, &FileExtractor::setTotalBytes);
|
||||||
|
QObject::connect(fileDownloader, &FileDownloader::readBytesChanged, this, &FileExtractor::setReadBytes);
|
||||||
|
|
||||||
|
QObject::connect(fileDownloader, &FileDownloader::downloadFinished,
|
||||||
|
[fileDownloader, timer, downloadStep, this]() mutable {
|
||||||
|
if (downloadStep++ == 0) {
|
||||||
|
fileDownloader->setUrl(QUrl(Constants::LinphoneBZip2_dll));
|
||||||
|
fileDownloader->download();
|
||||||
|
} else {
|
||||||
|
fileDownloader->deleteLater();
|
||||||
|
QObject::disconnect(fileDownloader, &FileDownloader::totalBytesChanged, this,
|
||||||
|
&FileExtractor::setTotalBytes);
|
||||||
|
QObject::disconnect(fileDownloader, &FileDownloader::readBytesChanged, this,
|
||||||
|
&FileExtractor::setReadBytes);
|
||||||
|
timer->start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(fileDownloader, &FileDownloader::downloadFailed, [fileDownloader, this]() {
|
||||||
|
fileDownloader->deleteLater();
|
||||||
|
emitExtractorFailed();
|
||||||
|
});
|
||||||
|
fileDownloader->download();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
mTimer->start();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileExtractor::remove() {
|
||||||
|
return QFile::exists(mDestinationFile) && QFile::remove(mDestinationFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileExtractor::getFile() const {
|
||||||
|
return mFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileExtractor::setFile(const QString &file) {
|
||||||
|
if (mExtracting) {
|
||||||
|
qWarning() << QStringLiteral("Unable to set file, a file is extracting.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mFile != file) {
|
||||||
|
mFile = file;
|
||||||
|
emit fileChanged(mFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileExtractor::getExtractFolder() const {
|
||||||
|
return mExtractFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileExtractor::setExtractFolder(const QString &extractFolder) {
|
||||||
|
if (mExtracting) {
|
||||||
|
qWarning() << QStringLiteral("Unable to set extract folder, a file is extracting.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mExtractFolder != extractFolder) {
|
||||||
|
mExtractFolder = extractFolder;
|
||||||
|
emit extractFolderChanged(mExtractFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileExtractor::getExtractName() const {
|
||||||
|
return mExtractName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileExtractor::setExtractName(const QString &extractName) {
|
||||||
|
if (mExtracting) {
|
||||||
|
qWarning() << QStringLiteral("Unable to set extract name, a file is extracting.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mExtractName != extractName) {
|
||||||
|
mExtractName = extractName;
|
||||||
|
emit extractNameChanged(mExtractName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileExtractor::getExtracting() const {
|
||||||
|
return mExtracting;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileExtractor::setExtracting(bool extracting) {
|
||||||
|
if (mExtracting != extracting) {
|
||||||
|
mExtracting = extracting;
|
||||||
|
emit extractingChanged(extracting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 FileExtractor::getReadBytes() const {
|
||||||
|
return mReadBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileExtractor::setReadBytes(qint64 readBytes) {
|
||||||
|
mReadBytes = readBytes;
|
||||||
|
emit readBytesChanged(readBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 FileExtractor::getTotalBytes() const {
|
||||||
|
return mTotalBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileExtractor::setTotalBytes(qint64 totalBytes) {
|
||||||
|
mTotalBytes = totalBytes;
|
||||||
|
emit totalBytesChanged(totalBytes);
|
||||||
|
}
|
||||||
|
void FileExtractor::clean() {
|
||||||
|
if (mTimer) {
|
||||||
|
mTimer->stop();
|
||||||
|
mTimer->deleteLater();
|
||||||
|
mTimer = nullptr;
|
||||||
|
}
|
||||||
|
setExtracting(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileExtractor::emitExtractorFailed() {
|
||||||
|
qWarning() << QStringLiteral("Unable to extract file `%1`. bzip2 is unavailable, please install it.").arg(mFile);
|
||||||
|
clean();
|
||||||
|
emit extractFailed();
|
||||||
|
}
|
||||||
|
void FileExtractor::emitExtractFailed(int error) {
|
||||||
|
qWarning() << QStringLiteral("Unable to extract file with bzip2: `%1` (code: %2).").arg(mFile).arg(error);
|
||||||
|
clean();
|
||||||
|
emit extractFailed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileExtractor::emitExtractFinished() {
|
||||||
|
clean();
|
||||||
|
emit extractFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileExtractor::emitOutputError() {
|
||||||
|
qWarning() << QStringLiteral("Could not write into `%1`.").arg(mDestinationFile);
|
||||||
|
clean();
|
||||||
|
emit extractFailed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileExtractor::handleExtraction() {
|
||||||
|
QString tempDestination = mDestinationFile + "." + QFileInfo(mFile).suffix();
|
||||||
|
QStringList args;
|
||||||
|
args.push_back("-dq");
|
||||||
|
args.push_back(tempDestination);
|
||||||
|
QFile::copy(mFile, tempDestination);
|
||||||
|
#ifdef WIN32
|
||||||
|
int result = QProcess::execute("bzip2.exe", args);
|
||||||
|
if (result == -2) result = QProcess::execute(Paths::getToolsDirPath() + "\\bzip2.exe", args);
|
||||||
|
#else
|
||||||
|
int result = QProcess::execute("bzip2", args);
|
||||||
|
#endif
|
||||||
|
if (QFile::exists(tempDestination)) QFile::remove(tempDestination);
|
||||||
|
if (result == 0) {
|
||||||
|
setReadBytes(getTotalBytes());
|
||||||
|
emitExtractFinished();
|
||||||
|
} else if (result > 0) emitExtractFailed(result);
|
||||||
|
else if (result == -2) emitExtractorFailed();
|
||||||
|
else emitOutputError();
|
||||||
|
}
|
||||||
104
Linphone/tool/file/FileExtractor.hpp
Normal file
104
Linphone/tool/file/FileExtractor.hpp
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-desktop
|
||||||
|
* (see https://www.linphone.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FILE_EXTRACTOR_H_
|
||||||
|
#define FILE_EXTRACTOR_H_
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
class QTimer;
|
||||||
|
|
||||||
|
// Supports only bzip file.
|
||||||
|
class FileExtractor : public QObject {
|
||||||
|
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
// TODO: Add an error property to use in UI.
|
||||||
|
|
||||||
|
Q_PROPERTY(QString file READ getFile WRITE setFile NOTIFY fileChanged);
|
||||||
|
Q_PROPERTY(QString extractFolder READ getExtractFolder WRITE setExtractFolder NOTIFY extractFolderChanged);
|
||||||
|
Q_PROPERTY(QString extractName READ getExtractName WRITE setExtractName NOTIFY extractNameChanged);
|
||||||
|
Q_PROPERTY(bool extracting READ getExtracting NOTIFY extractingChanged);
|
||||||
|
Q_PROPERTY(qint64 readBytes READ getReadBytes NOTIFY readBytesChanged);
|
||||||
|
Q_PROPERTY(qint64 totalBytes READ getTotalBytes NOTIFY totalBytesChanged);
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileExtractor(QObject *parent = nullptr);
|
||||||
|
~FileExtractor();
|
||||||
|
|
||||||
|
Q_INVOKABLE void extract();
|
||||||
|
Q_INVOKABLE bool remove();
|
||||||
|
|
||||||
|
QString getFile() const;
|
||||||
|
void setFile(const QString &file);
|
||||||
|
|
||||||
|
QString getExtractFolder() const;
|
||||||
|
void setExtractFolder(const QString &extractFolder);
|
||||||
|
|
||||||
|
QString getExtractName() const;
|
||||||
|
void setExtractName(const QString &extractName);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void fileChanged(const QString &file);
|
||||||
|
|
||||||
|
void extractFolderChanged(const QString &extractFolder);
|
||||||
|
void extractNameChanged(const QString &extractName);
|
||||||
|
|
||||||
|
void readBytesChanged(qint64 readBytes);
|
||||||
|
void totalBytesChanged(qint64 totalBytes);
|
||||||
|
|
||||||
|
void extractingChanged(bool extracting);
|
||||||
|
void extractFinished();
|
||||||
|
void extractFailed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
qint64 getReadBytes() const;
|
||||||
|
void setReadBytes(qint64 readBytes);
|
||||||
|
|
||||||
|
qint64 getTotalBytes() const;
|
||||||
|
void setTotalBytes(qint64 totalBytes);
|
||||||
|
|
||||||
|
bool getExtracting() const;
|
||||||
|
void setExtracting(bool extracting);
|
||||||
|
|
||||||
|
void clean();
|
||||||
|
|
||||||
|
void emitExtractFinished();
|
||||||
|
void emitExtractorFailed(); // Used when bzip2 cannot be used
|
||||||
|
void emitExtractFailed(int error);
|
||||||
|
void emitOutputError();
|
||||||
|
|
||||||
|
void handleExtraction();
|
||||||
|
|
||||||
|
QString mFile;
|
||||||
|
QString mExtractFolder;
|
||||||
|
QString mExtractName;
|
||||||
|
QString mDestinationFile;
|
||||||
|
|
||||||
|
bool mExtracting = false;
|
||||||
|
qint64 mReadBytes = 0;
|
||||||
|
qint64 mTotalBytes = 0;
|
||||||
|
|
||||||
|
QTimer *mTimer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILE_EXTRACTOR_H_
|
||||||
|
|
@ -12,6 +12,12 @@ RowLayout {
|
||||||
property bool enabled: true
|
property bool enabled: true
|
||||||
spacing : 20 * DefaultStyle.dp
|
spacing : 20 * DefaultStyle.dp
|
||||||
Layout.minimumHeight: 32 * DefaultStyle.dp
|
Layout.minimumHeight: 32 * DefaultStyle.dp
|
||||||
|
signal checkedChanged(bool checked)
|
||||||
|
|
||||||
|
function setChecked(value) {
|
||||||
|
switchButton.checked = value
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Text {
|
Text {
|
||||||
text: titleText
|
text: titleText
|
||||||
|
|
@ -34,9 +40,8 @@ RowLayout {
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
checked: propertyOwner[mainItem.propertyName]
|
checked: propertyOwner[mainItem.propertyName]
|
||||||
enabled: mainItem.enabled
|
enabled: mainItem.enabled
|
||||||
onToggled: {
|
onCheckedChanged: mainItem.checkedChanged(checked)
|
||||||
binding.when = true
|
onToggled: binding.when = true
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Binding {
|
Binding {
|
||||||
id: binding
|
id: binding
|
||||||
|
|
|
||||||
|
|
@ -684,34 +684,33 @@ function computeAvatarSize (container, maxSize, ratio) {
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
function openCodecOnlineInstallerDialog (window, codecInfo, cb) {
|
function openCodecOnlineInstallerDialog (mainWindow, coreObject, cancelCallBack, successCallBack) {
|
||||||
var VideoCodecsModel = Linphone.VideoCodecsModel
|
mainWindow.showConfirmationLambdaPopup("",
|
||||||
window.attachVirtualWindow(buildCommonDialogUri('ConfirmDialog'), {
|
qsTr("Installation de codec"),
|
||||||
descriptionText: qsTr('downloadCodecDescription')
|
qsTr("Télécharger le codec ") + capitalizeFirstLetter(coreObject.mimeType) + " ("+coreObject.encoderDescription+")"+" ?",
|
||||||
.replace('%1', codecInfo.mime)
|
function (confirmed) {
|
||||||
.replace('%2', codecInfo.encoderDescription)
|
if (confirmed) {
|
||||||
}, function (status) {
|
coreObject.success.connect(function() {
|
||||||
if (status) {
|
if (successCallBack)
|
||||||
window.attachVirtualWindow(buildLinphoneDialogUri('OnlineInstallerDialog'), {
|
successCallBack()
|
||||||
downloadUrl: codecInfo.downloadUrl,
|
mainWindow.closeLoadingPopup()
|
||||||
extract: true,
|
mainWindow.showInformationPopup(qsTr("Succès"), qsTr("Le codec a été téléchargé avec succès."), true)
|
||||||
installFolder: VideoCodecsModel.codecsFolder,
|
|
||||||
installName: codecInfo.installName,
|
|
||||||
mime: codecInfo.mime,
|
|
||||||
checksum: codecInfo.checksum
|
|
||||||
}, function (status) {
|
|
||||||
if (status) {
|
|
||||||
VideoCodecsModel.reload()
|
|
||||||
}
|
|
||||||
if (cb) {
|
|
||||||
cb(window)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
coreObject.extractError.connect(function() {
|
||||||
else if (cb) {
|
mainWindow.closeLoadingPopup()
|
||||||
cb(window)
|
mainWindow.showInformationPopup(qsTr("Erreur"), qsTr("Le codec n'a pas pu être sauvegardé."), true)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
coreObject.downloadError.connect(function() {
|
||||||
|
mainWindow.closeLoadingPopup()
|
||||||
|
mainWindow.showInformationPopup(qsTr("Erreur"), qsTr("Le codec n'a pas pu être téléchargé."), true)
|
||||||
|
})
|
||||||
|
mainWindow.showLoadingPopup(qsTr("Téléchargement en cours ..."))
|
||||||
|
coreObject.downloadAndExtract()
|
||||||
|
} else
|
||||||
|
if (cancelCallBack)
|
||||||
|
cancelCallBack()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function printObject(o) {
|
function printObject(o) {
|
||||||
|
|
|
||||||
|
|
@ -150,16 +150,43 @@ AbstractSettingsLayout {
|
||||||
Layout.leftMargin: 64 * DefaultStyle.dp
|
Layout.leftMargin: 64 * DefaultStyle.dp
|
||||||
Repeater {
|
Repeater {
|
||||||
model: PayloadTypeProxy {
|
model: PayloadTypeProxy {
|
||||||
|
id: videoPayloadTypeProxy
|
||||||
family: PayloadTypeCore.Video
|
family: PayloadTypeCore.Video
|
||||||
}
|
}
|
||||||
SwitchSetting {
|
SwitchSetting {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
titleText: Utils.capitalizeFirstLetter(modelData.core.mimeType)
|
titleText: Utils.capitalizeFirstLetter(modelData.core.mimeType)
|
||||||
subTitleText: modelData.core.recvFmtp
|
subTitleText: modelData.core.encoderDescription
|
||||||
propertyName: "enabled"
|
propertyName: "enabled"
|
||||||
propertyOwner: modelData.core
|
propertyOwner: modelData.core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Repeater {
|
||||||
|
model: PayloadTypeProxy {
|
||||||
|
id: downloadableVideoPayloadTypeProxy
|
||||||
|
family: PayloadTypeCore.Video
|
||||||
|
downloadable: true
|
||||||
|
}
|
||||||
|
SwitchSetting {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
titleText: Utils.capitalizeFirstLetter(modelData.core.mimeType)
|
||||||
|
subTitleText: modelData.core.encoderDescription
|
||||||
|
onCheckChanged: function(checked) {
|
||||||
|
if (checked)
|
||||||
|
UtilsCpp.getMainWindow().showConfirmationLambdaPopup("",
|
||||||
|
qsTr("Installation"),
|
||||||
|
qsTr("Télécharger le codec ") + Utils.capitalizeFirstLetter(modelData.core.mimeType) + " ("+modelData.core.encoderDescription+")"+" ?",
|
||||||
|
function (confirmed) {
|
||||||
|
if (confirmed) {
|
||||||
|
UtilsCpp.getMainWindow().showLoadingPopup(qsTr("Téléchargement en cours ..."))
|
||||||
|
modelData.core.downloadAndExtract()
|
||||||
|
} else
|
||||||
|
setChecked(false)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import QtQuick.Controls.Basic
|
||||||
import Linphone
|
import Linphone
|
||||||
import UtilsCpp
|
import UtilsCpp
|
||||||
import SettingsCpp
|
import SettingsCpp
|
||||||
|
import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils
|
||||||
|
|
||||||
AbstractWindow {
|
AbstractWindow {
|
||||||
id: mainWindow
|
id: mainWindow
|
||||||
|
|
@ -140,6 +141,7 @@ AbstractWindow {
|
||||||
onGoToRegister: mainWindowStackView.replace(registerPage)
|
onGoToRegister: mainWindowStackView.replace(registerPage)
|
||||||
onConnectionSucceed: {
|
onConnectionSucceed: {
|
||||||
openMainPage()
|
openMainPage()
|
||||||
|
proposeH264CodecsDownload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -156,6 +158,7 @@ AbstractWindow {
|
||||||
|
|
||||||
onConnectionSucceed: {
|
onConnectionSucceed: {
|
||||||
openMainPage()
|
openMainPage()
|
||||||
|
proposeH264CodecsDownload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -225,4 +228,25 @@ AbstractWindow {
|
||||||
// StackView.onActivated: connectionSecured(0) // TODO : connect to cpp part when ready
|
// StackView.onActivated: connectionSecured(0) // TODO : connect to cpp part when ready
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// H264 Cisco codec download
|
||||||
|
PayloadTypeProxy {
|
||||||
|
id: downloadableVideoPayloadTypeProxy
|
||||||
|
family: PayloadTypeCore.Video
|
||||||
|
downloadable: true
|
||||||
|
}
|
||||||
|
Repeater {
|
||||||
|
id: codecDownloader
|
||||||
|
model: null
|
||||||
|
Item {
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (modelData.core.mimeType == "H264")
|
||||||
|
Utils.openCodecOnlineInstallerDialog(mainWindow, modelData.core)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function proposeH264CodecsDownload() {
|
||||||
|
codecDownloader.model = downloadableVideoPayloadTypeProxy
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue