diff --git a/CMakeLists.txt b/CMakeLists.txt index 902a76fb63091c5926e565ccf17e202898c17d00..7a22b6bde094133a50668e978ec6c4aa978f4a9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -328,6 +328,7 @@ SET( libringclient_LIB_SRCS src/contactmodel.cpp src/newcallmodel.cpp src/newdevicemodel.cpp + src/newcodecmodel.cpp src/conversationmodel.cpp src/database.cpp src/authority/daemon.cpp @@ -499,6 +500,7 @@ SET(libringclient_api_LIB_HDRS src/api/lrc.h src/api/newaccountmodel.h src/api/newcallmodel.h + src/api/newcodecmodel.h src/api/newdevicemodel.h src/api/contactmodel.h src/api/conversationmodel.h diff --git a/src/api/account.h b/src/api/account.h index 6f9b6c684d48dc4f4ce48e4635f461eb2c8495cf..d45b26849a24cf87b6cff3eea77cc2187c6f1ee5 100644 --- a/src/api/account.h +++ b/src/api/account.h @@ -39,6 +39,7 @@ class ContactModel; class ConversationModel; class NewAccountModel; class NewDeviceModel; +class NewCodecModel; namespace account { @@ -181,6 +182,7 @@ struct Info std::unique_ptr<lrc::api::ContactModel> contactModel; std::unique_ptr<lrc::api::ConversationModel> conversationModel; std::unique_ptr<lrc::api::NewDeviceModel> deviceModel; + std::unique_ptr<lrc::api::NewCodecModel> codecModel; NewAccountModel* accountModel {nullptr}; // daemon config diff --git a/src/api/newcodecmodel.h b/src/api/newcodecmodel.h new file mode 100644 index 0000000000000000000000000000000000000000..2590f7f00df8c6247b4a088ce40e7e16d2d9dbb9 --- /dev/null +++ b/src/api/newcodecmodel.h @@ -0,0 +1,105 @@ +/**************************************************************************** + * Copyright (C) 2018 Savoir-faire Linux * + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser 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/>. * + ***************************************************************************/ +#pragma once + +// Std +#include <memory> +#include <string> +#include <list> + +// Qt +#include <qobject.h> +#include <QObject> + +// Lrc +#include "api/account.h" +#include "typedefs.h" + +namespace lrc +{ + +class CallbacksHandler; +class NewCodecModelPimpl; + +namespace api +{ + +namespace account { struct Info; } + +struct Codec +{ + unsigned int id; + bool enabled; + std::string name; + std::string samplerate; + std::string bitrate; + std::string min_bitrate; + std::string max_bitrate; + std::string type; + std::string quality; + std::string min_quality; + std::string max_quality; + bool auto_quality_enabled; +}; + +/** + * @brief Class that manages ring devices for an account + */ +class LIB_EXPORT NewCodecModel : public QObject { + Q_OBJECT + +public: + const account::Info& owner; + + NewCodecModel(const account::Info& owner, const CallbacksHandler& callbacksHandler); + ~NewCodecModel(); + + /** + * @return audio codecs for the account + */ + std::list<Codec> getAudioCodecs() const; + /** + * @return video codecs for the account + */ + std::list<Codec> getVideoCodecs() const; + /** + * Set a higher priority to a codec + * @param codecId + * @param isVideo + */ + void increasePriority(const unsigned int& codecid, bool isVideo); + /** + * Set a lower priority to a codec + * @param codecId + * @param isVideo + */ + void decreasePriority(const unsigned int& codecid, bool isVideo); + /** + * Enable a codec + * @param codecId + * @param enabled true if enabled else false + * @return if codecId is the only codec impacted + */ + bool enable(const unsigned int& codecid, bool enabled); + +private: + std::unique_ptr<NewCodecModelPimpl> pimpl_; +}; + +} // namespace api +} // namespace lrc diff --git a/src/newaccountmodel.cpp b/src/newaccountmodel.cpp index 4844bbc62b223a51e577650530fd4b0a7d6f715e..7465890b248a55fb3730fb75d8db78d4ab7dd71d 100644 --- a/src/newaccountmodel.cpp +++ b/src/newaccountmodel.cpp @@ -26,6 +26,7 @@ #include "api/newcallmodel.h" #include "api/contactmodel.h" #include "api/conversationmodel.h" +#include "api/newcodecmodel.h" #include "api/newdevicemodel.h" #include "api/account.h" #include "api/behaviorcontroller.h" @@ -319,6 +320,7 @@ NewAccountModelPimpl::addToAccounts(const std::string& accountId) owner.contactModel = std::make_unique<ContactModel>(owner, database, callbacksHandler); owner.conversationModel = std::make_unique<ConversationModel>(owner, lrc, database, callbacksHandler, behaviorController); owner.deviceModel = std::make_unique<NewDeviceModel>(owner, callbacksHandler); + owner.codecModel = std::make_unique<NewCodecModel>(owner, callbacksHandler); owner.accountModel = &linked; MapStringString volatileDetails = ConfigurationManager::instance().getVolatileAccountDetails(accountId.c_str()); owner.status = lrc::api::account::to_status(toStdString(volatileDetails[ConfProperties::Registration::STATUS])); diff --git a/src/newcodecmodel.cpp b/src/newcodecmodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c73ef771f63e38ac463471e96bfbd60c992d707e --- /dev/null +++ b/src/newcodecmodel.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** + * Copyright (C) 2017-2018 Savoir-faire Linux * + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser 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 "api/newcodecmodel.h" + +// std +#include <list> +#include <mutex> + +// LRC +#include "callbackshandler.h" +#include "dbus/configurationmanager.h" + +// Daemon +#include <account_const.h> + +// Qt +#include <QObject> + +namespace lrc +{ + + +using namespace api; + +class NewCodecModelPimpl: public QObject +{ + Q_OBJECT +public: + NewCodecModelPimpl(const NewCodecModel& linked, const CallbacksHandler& callbacksHandler); + ~NewCodecModelPimpl(); + + std::list<Codec> videoCodecs; + std::mutex audioCodecsMtx; + std::list<Codec> audioCodecs; + std::mutex videoCodecsMtx; + + const CallbacksHandler& callbacksHandler; + const NewCodecModel& linked; + + void setActiveCodecs(); + +private: + void addCodec(const unsigned int& id, const QVector<unsigned int>& activeCodecs); +}; + +NewCodecModel::NewCodecModel(const account::Info& owner, const CallbacksHandler& callbacksHandler) +: owner(owner) +, pimpl_(std::make_unique<NewCodecModelPimpl>(*this, callbacksHandler)) +{ } + +NewCodecModel::~NewCodecModel() {} + +std::list<Codec> +NewCodecModel::getAudioCodecs() const +{ + return pimpl_->audioCodecs; +} + +std::list<Codec> +NewCodecModel::getVideoCodecs() const +{ + return pimpl_->videoCodecs; +} + +void +NewCodecModel::increasePriority(const unsigned int& codecId, bool isVideo) +{ + auto& codecs = isVideo? pimpl_->videoCodecs : pimpl_->audioCodecs; + auto& mutex = isVideo? pimpl_->videoCodecsMtx : pimpl_->audioCodecsMtx; + { + std::unique_lock<std::mutex> lock(mutex); + auto it = codecs.begin(); + if (codecs.begin()->id == codecId) { + // Already at top, abort + return; + } + while (it != codecs.end()) { + if (it->id == codecId) { + std::swap(*it, *it--); + break; + } + it++; + } + } + pimpl_->setActiveCodecs(); +} + +void +NewCodecModel::decreasePriority(const unsigned int& codecId, bool isVideo) +{ + auto& codecs = isVideo? pimpl_->videoCodecs : pimpl_->audioCodecs; + auto& mutex = isVideo? pimpl_->videoCodecsMtx : pimpl_->audioCodecsMtx; + { + std::unique_lock<std::mutex> lock(mutex); + auto it = codecs.begin(); + if (codecs.rbegin()->id == codecId) { + // Already at bottom, abort + return; + } + while (it != codecs.end()) { + if (it->id == codecId) { + std::swap(*it, *it++); + break; + } + it++; + } + } + pimpl_->setActiveCodecs(); +} + +bool +NewCodecModel::enable(const unsigned int& codecId, bool enabled) +{ + auto redraw = false; + auto isAudio = true; + { + std::unique_lock<std::mutex> lock(pimpl_->audioCodecsMtx); + auto allDisabled = true; + for (auto& codec : pimpl_->videoCodecs) { + if (codec.id == codecId) { + if (codec.enabled == enabled) return redraw; + codec.enabled = enabled; + isAudio = false; + } + if (codec.enabled) { + allDisabled = false; + } + } + if (allDisabled) { + redraw = true; + // Disabling all codecs is not possible and the daemon set enabled all codecs here + // So, set all codecs enabled + for (auto& codec : pimpl_->videoCodecs) { + codec.enabled = true; + } + } + } + if (isAudio) { + std::unique_lock<std::mutex> lock(pimpl_->audioCodecsMtx); + auto allDisabled = true; + for (auto& codec : pimpl_->audioCodecs) { + if (codec.id == codecId) { + if (codec.enabled == enabled) return redraw; + codec.enabled = enabled; + } + if (codec.enabled) { + allDisabled = false; + } + } + if (allDisabled) { + redraw = true; + // Disabling all codecs is not possible and the daemon set enabled all codecs here + // So, set all codecs enabled + for (auto& codec : pimpl_->audioCodecs) { + codec.enabled = true; + } + } + } + pimpl_->setActiveCodecs(); + return redraw; +} + +NewCodecModelPimpl::NewCodecModelPimpl(const NewCodecModel& linked, const CallbacksHandler& callbacksHandler) +: linked(linked) +, callbacksHandler(callbacksHandler) +{ + QVector<unsigned int> codecsList = ConfigurationManager::instance().getCodecList(); + QVector<unsigned int> activeCodecs = ConfigurationManager::instance().getActiveCodecList(linked.owner.id.c_str()); + for (const auto& id : activeCodecs) { + addCodec(id, activeCodecs); + } + for (const auto& id : codecsList) { + if (activeCodecs.indexOf(id) != -1) continue; + addCodec(id, activeCodecs); + } +} + +NewCodecModelPimpl::~NewCodecModelPimpl() +{ + +} + +void +NewCodecModelPimpl::setActiveCodecs() +{ + QVector<unsigned int> enabledCodecs; + { + std::unique_lock<std::mutex> lock(videoCodecsMtx); + for (auto& codec : videoCodecs) { + if (codec.enabled) { + enabledCodecs.push_back(codec.id); + } + } + } + { + std::unique_lock<std::mutex> lock(audioCodecsMtx); + for (auto& codec : audioCodecs) { + if (codec.enabled) { + enabledCodecs.push_back(codec.id); + } + } + } + ConfigurationManager::instance().setActiveCodecList(linked.owner.id.c_str(), enabledCodecs); +} + +void +NewCodecModelPimpl::addCodec(const unsigned int& id, const QVector<unsigned int>& activeCodecs) +{ + MapStringString details = ConfigurationManager::instance().getCodecDetails(linked.owner.id.c_str(), id); + Codec codec; + codec.id = id; + codec.enabled = activeCodecs.indexOf(id) != -1; + codec.name = details[DRing::Account::ConfProperties::CodecInfo::NAME].toStdString(); + codec.samplerate = details[DRing::Account::ConfProperties::CodecInfo::SAMPLE_RATE].toStdString(); + codec.bitrate = details[DRing::Account::ConfProperties::CodecInfo::BITRATE].toStdString(); + codec.min_bitrate = details[DRing::Account::ConfProperties::CodecInfo::MIN_BITRATE].toStdString(); + codec.max_bitrate = details[DRing::Account::ConfProperties::CodecInfo::MAX_BITRATE].toStdString(); + codec.type = details[DRing::Account::ConfProperties::CodecInfo::TYPE].toStdString(); + codec.quality = details[DRing::Account::ConfProperties::CodecInfo::QUALITY].toStdString(); + codec.min_quality = details[DRing::Account::ConfProperties::CodecInfo::MIN_QUALITY].toStdString(); + codec.max_quality = details[DRing::Account::ConfProperties::CodecInfo::MAX_QUALITY].toStdString(); + codec.auto_quality_enabled = details[DRing::Account::ConfProperties::CodecInfo::AUTO_QUALITY_ENABLED].toStdString() == "true"; + if (codec.type == "AUDIO") { + std::unique_lock<std::mutex> lock(audioCodecsMtx); + audioCodecs.emplace_back(codec); + } else { + std::unique_lock<std::mutex> lock(videoCodecsMtx); + videoCodecs.emplace_back(codec); + } +} + +} // namespace lrc + +#include "newcodecmodel.moc" +#include "api/moc_newcodecmodel.cpp"