mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-07-25 18:05:34 +02:00
feature: Add 'advanced information' call overlay
Change-Id: Ia54d01ec56e01d0c04e360ec06da87aa37fe74fe GitLab: #510
This commit is contained in:
parent
8a59035c8a
commit
7e9dce9c00
24 changed files with 432 additions and 252 deletions
|
@ -46,6 +46,10 @@ AvAdapter::AvAdapter(LRCInstance* instance, QObject* parent)
|
|||
&lrc::api::AVModel::rendererStarted,
|
||||
this,
|
||||
&AvAdapter::onRendererStarted);
|
||||
connect(&lrcInstance_->avModel(),
|
||||
&lrc::api::AVModel::onRendererInfosUpdated,
|
||||
this,
|
||||
&AvAdapter::setRenderersInfoList);
|
||||
}
|
||||
|
||||
// The top left corner of primary screen is (0, 0).
|
||||
|
@ -415,8 +419,15 @@ AvAdapter::getHardwareAcceleration()
|
|||
{
|
||||
return lrcInstance_->avModel().getHardwareAcceleration();
|
||||
}
|
||||
|
||||
void
|
||||
AvAdapter::setHardwareAcceleration(bool accelerate)
|
||||
{
|
||||
lrcInstance_->avModel().setHardwareAcceleration(accelerate);
|
||||
}
|
||||
|
||||
void
|
||||
AvAdapter::setRenderersInfoList(QVariantList renderersInfo)
|
||||
{
|
||||
set_renderersInfoList(renderersInfo);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ class AvAdapter final : public QmlAdapterBase
|
|||
QML_PROPERTY(bool, muteCamera)
|
||||
QML_RO_PROPERTY(QStringList, windowsNames)
|
||||
QML_RO_PROPERTY(QList<QVariant>, windowsIds)
|
||||
QML_RO_PROPERTY(QVariantList, renderersInfoList)
|
||||
|
||||
public:
|
||||
explicit AvAdapter(LRCInstance* instance, QObject* parent = nullptr);
|
||||
|
@ -107,6 +108,7 @@ protected:
|
|||
Q_INVOKABLE void setHardwareAcceleration(bool accelerate);
|
||||
|
||||
private Q_SLOTS:
|
||||
void setRenderersInfoList(QVariantList renderersInfo);
|
||||
void onAudioDeviceEvent();
|
||||
void onRendererStarted(const QString& id, const QSize& size);
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ CallAdapter::CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject*
|
|||
: QmlAdapterBase(instance, parent)
|
||||
, systemTray_(systemTray)
|
||||
{
|
||||
timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, &CallAdapter::updateAdvancedInformation);
|
||||
|
||||
participantsModel_.reset(new CallParticipantsModel(lrcInstance_, this));
|
||||
QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, participantsModel_.get(), "CallParticipantsModel");
|
||||
|
||||
|
@ -95,6 +98,19 @@ CallAdapter::CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject*
|
|||
&CallAdapter::saveConferenceSubcalls);
|
||||
}
|
||||
|
||||
void
|
||||
CallAdapter::startTimerInformation()
|
||||
{
|
||||
updateAdvancedInformation();
|
||||
timer->start(1000);
|
||||
}
|
||||
|
||||
void
|
||||
CallAdapter::stopTimerInformation()
|
||||
{
|
||||
timer->stop();
|
||||
}
|
||||
|
||||
void
|
||||
CallAdapter::onAccountChanged()
|
||||
{
|
||||
|
@ -1147,6 +1163,18 @@ CallAdapter::getCallDurationTime(const QString& accountId, const QString& convUi
|
|||
return QString();
|
||||
}
|
||||
|
||||
void
|
||||
CallAdapter::updateAdvancedInformation()
|
||||
{
|
||||
try {
|
||||
auto& callModel = lrcInstance_->accountModel().getAccountInfo(accountId_).callModel;
|
||||
if (callModel)
|
||||
set_callInformation(QVariantList::fromList(callModel->getAdvancedInformation()));
|
||||
} catch (const std::exception& e) {
|
||||
qWarning() << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CallAdapter::preventScreenSaver(bool state)
|
||||
{
|
||||
|
|
|
@ -37,8 +37,10 @@ class CallAdapter final : public QmlAdapterBase
|
|||
{
|
||||
Q_OBJECT
|
||||
QML_PROPERTY(bool, hasCall)
|
||||
QML_RO_PROPERTY(QVariantList, callInformation)
|
||||
|
||||
public:
|
||||
QTimer* timer;
|
||||
enum MuteStates { UNMUTED, LOCAL_MUTED, MODERATOR_MUTED, BOTH_MUTED };
|
||||
Q_ENUM(MuteStates)
|
||||
|
||||
|
@ -49,6 +51,8 @@ protected:
|
|||
void safeInit() override {};
|
||||
|
||||
public:
|
||||
Q_INVOKABLE void startTimerInformation();
|
||||
Q_INVOKABLE void stopTimerInformation();
|
||||
Q_INVOKABLE void placeAudioOnlyCall();
|
||||
Q_INVOKABLE void placeCall();
|
||||
Q_INVOKABLE void hangUpACall(const QString& accountId, const QString& convUid);
|
||||
|
@ -88,6 +92,7 @@ public:
|
|||
const QString& accountId = {},
|
||||
bool forceCallOnly = false);
|
||||
Q_INVOKABLE QString getCallDurationTime(const QString& accountId, const QString& convUid);
|
||||
Q_INVOKABLE void updateAdvancedInformation();
|
||||
|
||||
Q_SIGNALS:
|
||||
void callStatusChanged(int index, const QString& accountId, const QString& convUid);
|
||||
|
|
|
@ -291,6 +291,7 @@ Item {
|
|||
property string shareFile: qsTr("Share file")
|
||||
property string selectShareMethod: qsTr("Select sharing method")
|
||||
property string viewPlugin: qsTr("View plugin")
|
||||
property string advancedInformation: qsTr("Advanced information")
|
||||
property string noVideoDevice: qsTr("No video device")
|
||||
property string notAvailable: qsTr("Unavailable")
|
||||
property string lowerHand: qsTr("Lower hand")
|
||||
|
|
|
@ -344,6 +344,13 @@ Item {
|
|||
property real swarmDetailsPageDocumentsPaperClipSize: 24
|
||||
property real swarmDetailsPageDocumentsMediaSize: 175
|
||||
|
||||
//Call information
|
||||
property real textFontPointSize: calcSize(10)
|
||||
property real titleFontPointSize: calcSize(13)
|
||||
property color callInfoColor: chatviewTextColor
|
||||
property int callInformationElementsSpacing: 5
|
||||
property int callInformationBlockSpacing: 25
|
||||
|
||||
// Jami switch
|
||||
property real switchIndicatorRadius: 30
|
||||
property real switchPreferredHeight: 25
|
||||
|
|
213
src/app/mainview/components/CallInformationWindow.qml
Normal file
213
src/app/mainview/components/CallInformationWindow.qml
Normal file
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Savoir-faire Linux Inc.
|
||||
* Author: Nicolas Vengeon <nicolas.vengeon@savoirfairelinux.com>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import "../../commoncomponents"
|
||||
|
||||
Window {
|
||||
id: root
|
||||
|
||||
width: parent.width * 2 / 3
|
||||
height: parent.height * 2 / 3
|
||||
property var advancedList
|
||||
property var fps
|
||||
|
||||
onClosing: {
|
||||
CallAdapter.stopTimerInformation()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: container
|
||||
|
||||
anchors.fill: parent
|
||||
color: JamiTheme.secondaryBackgroundColor
|
||||
|
||||
RowLayout {
|
||||
id: windowContent
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
ColumnLayout {
|
||||
spacing: JamiTheme.callInformationBlockSpacing
|
||||
|
||||
Text{
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Call information"
|
||||
font.pointSize: JamiTheme.titleFontPointSize
|
||||
}
|
||||
|
||||
Item {
|
||||
id: itemCallInformation
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
clip: true
|
||||
|
||||
ListView {
|
||||
model: advancedList
|
||||
width: parent.width
|
||||
height: root.height
|
||||
spacing: JamiTheme.callInformationBlockSpacing
|
||||
|
||||
delegate: Column {
|
||||
spacing: JamiTheme.callInformationElementsSpacing
|
||||
|
||||
Text {
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Call id: " + modelData.CALL_ID
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemCallInformation.width
|
||||
}
|
||||
|
||||
Text {
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Video codec: " + modelData.VIDEO_CODEC
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemCallInformation.width
|
||||
}
|
||||
|
||||
Text {
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Audio codec: " + modelData.AUDIO_CODEC
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemCallInformation.width
|
||||
}
|
||||
|
||||
Text {
|
||||
function stringWithoutRing(peerNumber){
|
||||
return peerNumber.replace("@ring.dht","") ;
|
||||
}
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "PEER_NUMBER: " + stringWithoutRing(modelData.PEER_NUMBER)
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemCallInformation.width
|
||||
}
|
||||
|
||||
Text {
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Hardware acceleration: " + modelData.HARDWARE_ACCELERATION
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemCallInformation.width
|
||||
}
|
||||
|
||||
Text {
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Video min bitrate: " + modelData.VIDEO_MIN_BITRATE
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemCallInformation.width
|
||||
}
|
||||
|
||||
Text {
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Video max bitrate: " + modelData.VIDEO_MAX_BITRATE
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemCallInformation.width
|
||||
}
|
||||
|
||||
Text {
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Video bitrate: " + modelData.VIDEO_BITRATE
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemCallInformation.width
|
||||
}
|
||||
|
||||
Text {
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Sockets: " + modelData.SOCKETS
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemCallInformation.width
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: JamiTheme.callInformationBlockSpacing
|
||||
|
||||
Text {
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Renderers information"
|
||||
font.pointSize: JamiTheme.titleFontPointSize
|
||||
}
|
||||
|
||||
Item {
|
||||
id: itemParticipantInformation
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
clip: true
|
||||
|
||||
|
||||
ListView {
|
||||
width: parent.width
|
||||
height: root.height
|
||||
spacing: JamiTheme.callInformationBlockSpacing
|
||||
model: fps
|
||||
|
||||
delegate: Column {
|
||||
spacing: JamiTheme.callInformationElementsSpacing
|
||||
|
||||
Text{
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Renderer id: " + modelData.ID
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemParticipantInformation.width
|
||||
}
|
||||
|
||||
Text {
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Fps: " + modelData.FPS
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemParticipantInformation.width
|
||||
}
|
||||
|
||||
Text {
|
||||
color: JamiTheme.callInfoColor
|
||||
text: "Resolution: " + modelData.RES
|
||||
font.pointSize: JamiTheme.textFontPointSize
|
||||
wrapMode: Text.WrapAnywhere
|
||||
width: itemParticipantInformation.width
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -83,6 +83,7 @@ Item {
|
|||
SelectScreenWindowCreation.destroySelectScreenWindow()
|
||||
ScreenRubberBandCreation.destroyScreenRubberBandWindow()
|
||||
PluginHandlerPickerCreation.closePluginHandlerPicker()
|
||||
callInformationWindow.close()
|
||||
}
|
||||
|
||||
// x, y position does not need to be translated
|
||||
|
@ -123,6 +124,14 @@ Item {
|
|||
y: root.height / 2 - sipInputPanel.height / 2
|
||||
}
|
||||
|
||||
CallInformationWindow {
|
||||
id: callInformationWindow
|
||||
|
||||
visible: false
|
||||
advancedList: CallAdapter.callInformation
|
||||
fps: AvAdapter.renderersInfoList
|
||||
}
|
||||
|
||||
JamiFileDialog {
|
||||
id: jamiFileDialog
|
||||
|
||||
|
|
|
@ -176,6 +176,18 @@ ContextMenuAutoLoader {
|
|||
onClicked: {
|
||||
root.pluginItemClicked()
|
||||
}
|
||||
},
|
||||
GeneralMenuItem {
|
||||
id: advancedInformation
|
||||
|
||||
canTrigger: true
|
||||
itemName: JamiStrings.advancedInformation
|
||||
iconSource: JamiResources.settings_24dp_svg
|
||||
|
||||
onClicked: {
|
||||
CallAdapter.startTimerInformation();
|
||||
callInformationWindow.show()
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -151,6 +151,7 @@ Rectangle {
|
|||
|
||||
Rectangle {
|
||||
id: callPageMainRect
|
||||
|
||||
SplitView.preferredHeight: mainColumnLayout.isHorizontal ? root.height : (root.height / 3) * 2
|
||||
SplitView.preferredWidth: mainColumnLayout.isHorizontal ? (root.width / 3) * 2 : root.width
|
||||
SplitView.minimumHeight: root.height / 2 + 20
|
||||
|
|
|
@ -212,5 +212,6 @@
|
|||
<file>mainview/components/DocumentsScrollview.qml</file>
|
||||
<file>mainview/components/FilePreview.qml</file>
|
||||
<file>mainview/components/MediaPreview.qml</file>
|
||||
<file>mainview/components/CallInformationWindow.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -278,7 +278,6 @@ set(LIBCLIENT_SOURCES
|
|||
avmodel.cpp
|
||||
pluginmodel.cpp
|
||||
namedirectory.cpp
|
||||
smartinfohub.cpp
|
||||
renderer.cpp)
|
||||
|
||||
set(LIBCLIENT_HEADERS
|
||||
|
@ -286,7 +285,6 @@ set(LIBCLIENT_HEADERS
|
|||
globalinstances.h
|
||||
pixmapmanipulatordefault.h
|
||||
dbuserrorhandlerdefault.h
|
||||
smartinfohub.h
|
||||
vcard.h
|
||||
namedirectory.h
|
||||
messagelistmodel.h
|
||||
|
|
|
@ -276,8 +276,17 @@ public:
|
|||
QSize getRendererSize(const QString& id);
|
||||
video::Frame getRendererFrame(const QString& id);
|
||||
bool useDirectRenderer() const;
|
||||
/**
|
||||
* Update renderers information list
|
||||
*/
|
||||
Q_SLOT void updateRenderersInfo();
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted after an update of renderers information
|
||||
* @param renderersInfoList Information on all renderers (RES, ID, FPS)
|
||||
*/
|
||||
void onRendererInfosUpdated(QVariantList renderersInfoList);
|
||||
/**
|
||||
* Emitted when a renderer is started
|
||||
* @param id of the renderer
|
||||
|
|
|
@ -391,6 +391,12 @@ public:
|
|||
QString getDisplay(const QString& windowId);
|
||||
|
||||
void emplaceConversationConference(const QString& callId);
|
||||
|
||||
/**
|
||||
* Get advanced information from every current call
|
||||
*/
|
||||
QList<QVariant> getAdvancedInformation() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
|
|
|
@ -168,6 +168,23 @@ AVModel::~AVModel()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
AVModel::updateRenderersInfo()
|
||||
{
|
||||
QVariantList renderersInfoList;
|
||||
|
||||
for (auto r = pimpl_->renderers_.begin(); r != pimpl_->renderers_.end(); r++) {
|
||||
QVariantMap qmap;
|
||||
auto& rend = r->second;
|
||||
MapStringString mapInfo = rend->getInfos();
|
||||
qmap.insert(rend->RES, mapInfo["RES"]);
|
||||
qmap.insert(rend->ID, mapInfo["ID"]);
|
||||
qmap.insert(rend->FPS, mapInfo["FPS"]);
|
||||
renderersInfoList.append(qmap);
|
||||
}
|
||||
Q_EMIT onRendererInfosUpdated(renderersInfoList);
|
||||
}
|
||||
|
||||
bool
|
||||
AVModel::getDecodingAccelerated() const
|
||||
{
|
||||
|
@ -197,7 +214,7 @@ AVModel::setEncodingAccelerated(bool accelerate)
|
|||
bool
|
||||
AVModel::getHardwareAcceleration() const
|
||||
{
|
||||
bool result = getDecodingAccelerated() & getEncodingAccelerated();
|
||||
bool result = getDecodingAccelerated() && getEncodingAccelerated();
|
||||
return result;
|
||||
}
|
||||
void
|
||||
|
@ -825,6 +842,12 @@ void
|
|||
AVModelPimpl::addRenderer(const QString& id, const QSize& res, const QString& shmPath)
|
||||
{
|
||||
auto connectRenderer = [this](Renderer* renderer, const QString& id) {
|
||||
connect(
|
||||
renderer,
|
||||
&Renderer::fpsChanged,
|
||||
this,
|
||||
[this, id](void) { Q_EMIT linked_.updateRenderersInfo(); },
|
||||
Qt::DirectConnection);
|
||||
connect(
|
||||
renderer,
|
||||
&Renderer::started,
|
||||
|
|
|
@ -55,8 +55,12 @@
|
|||
|
||||
using namespace libjami::Media;
|
||||
|
||||
constexpr static const char HARDWARE_ACCELERATION[] = "HARDWARE_ACCELERATION";
|
||||
constexpr static const char CALL_ID[] = "CALL_ID";
|
||||
|
||||
static std::uniform_int_distribution<int> dis {0, std::numeric_limits<int>::max()};
|
||||
static const std::map<short, QString>
|
||||
|
||||
sip_call_status_code_map {{0, QObject::tr("Null")},
|
||||
{100, QObject::tr("Trying")},
|
||||
{180, QObject::tr("Ringing")},
|
||||
|
@ -128,6 +132,8 @@ public:
|
|||
const BehaviorController& behaviorController);
|
||||
~CallModelPimpl();
|
||||
|
||||
QVariantList callAdvancedInformation();
|
||||
|
||||
/**
|
||||
* Send the profile VCard into a call
|
||||
* @param callId
|
||||
|
@ -397,6 +403,12 @@ CallModel::createCall(const QString& uri, bool isAudioOnly, VectorMapStringStrin
|
|||
return callId;
|
||||
}
|
||||
|
||||
QList<QVariant>
|
||||
CallModel::getAdvancedInformation() const
|
||||
{
|
||||
return pimpl_->callAdvancedInformation();
|
||||
}
|
||||
|
||||
void
|
||||
CallModel::muteMedia(const QString& callId, const QString& label, bool mute)
|
||||
{
|
||||
|
@ -950,6 +962,25 @@ CallModelPimpl::CallModelPimpl(const CallModel& linked,
|
|||
|
||||
CallModelPimpl::~CallModelPimpl() {}
|
||||
|
||||
QVariantList
|
||||
CallModelPimpl::callAdvancedInformation()
|
||||
{
|
||||
QVariantList advancedInformationList;
|
||||
|
||||
QStringList callList = CallManager::instance().getCallList(linked.owner.id);
|
||||
for (const auto& callId : callList) {
|
||||
MapStringString mapStringDetailsList = CallManager::instance()
|
||||
.getCallDetails(linked.owner.id, callId);
|
||||
QVariantMap detailsList = mapStringStringToQVariantMap(mapStringDetailsList);
|
||||
|
||||
detailsList.insert(CALL_ID, callId);
|
||||
detailsList.insert(HARDWARE_ACCELERATION, lrc.getAVModel().getHardwareAcceleration());
|
||||
advancedInformationList.append(detailsList);
|
||||
}
|
||||
|
||||
return advancedInformationList;
|
||||
}
|
||||
|
||||
void
|
||||
CallModelPimpl::initCallFromDaemon()
|
||||
{
|
||||
|
|
|
@ -33,10 +33,19 @@ using namespace lrc::api::video;
|
|||
struct DirectRenderer::Impl : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
int fpsC;
|
||||
int fps;
|
||||
|
||||
public:
|
||||
std::chrono::time_point<std::chrono::system_clock> lastFrameDebug;
|
||||
|
||||
Impl(DirectRenderer* parent)
|
||||
: QObject(nullptr)
|
||||
, parent_(parent)
|
||||
, fpsC(0)
|
||||
, fps(0)
|
||||
, lastFrameDebug(std::chrono::system_clock::now())
|
||||
{
|
||||
configureTarget();
|
||||
if (!VideoManager::instance().registerSinkTarget(parent_->id(), target))
|
||||
|
@ -81,6 +90,16 @@ public:
|
|||
QMutexLocker lk(&mutex);
|
||||
frameBufferPtr = std::move(buf);
|
||||
}
|
||||
// compute FPS
|
||||
++fpsC;
|
||||
auto currentTime = std::chrono::system_clock::now();
|
||||
const std::chrono::duration<double> seconds = currentTime - lastFrameDebug;
|
||||
if (seconds.count() >= FPS_RATE_SEC) {
|
||||
fps = static_cast<int>(fpsC / seconds.count());
|
||||
fpsC = 0;
|
||||
lastFrameDebug = currentTime;
|
||||
parent_->setFPS(fps);
|
||||
}
|
||||
|
||||
Q_EMIT parent_->frameUpdated();
|
||||
};
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
/* widget_p.h (_p means private) */
|
||||
#include <QObject>
|
||||
#include "../smartinfohub.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
#pragma once
|
||||
|
|
|
@ -43,6 +43,16 @@
|
|||
#define LOG_LIBJAMI_SIGNAL4(name, arg, arg2, arg3, arg4)
|
||||
#endif
|
||||
|
||||
inline QVariantMap
|
||||
mapStringStringToQVariantMap(const MapStringString& map)
|
||||
{
|
||||
QVariantMap convertedMap;
|
||||
for (auto i = map.begin(); i != map.end(); i++) {
|
||||
convertedMap.insert(i.key(), i.value());
|
||||
}
|
||||
return convertedMap;
|
||||
}
|
||||
|
||||
inline MapStringString
|
||||
convertMap(const std::map<std::string, std::string>& m)
|
||||
{
|
||||
|
|
|
@ -34,6 +34,12 @@ Renderer::Renderer(const QString& id, const QSize& res)
|
|||
|
||||
Renderer::~Renderer() {}
|
||||
|
||||
int
|
||||
Renderer::fps() const
|
||||
{
|
||||
return fps_;
|
||||
}
|
||||
|
||||
QString
|
||||
Renderer::id() const
|
||||
{
|
||||
|
@ -45,6 +51,22 @@ Renderer::size() const
|
|||
{
|
||||
return size_;
|
||||
}
|
||||
void
|
||||
Renderer::setFPS(int fps)
|
||||
{
|
||||
fps_ = fps;
|
||||
Q_EMIT fpsChanged();
|
||||
}
|
||||
|
||||
MapStringString
|
||||
Renderer::getInfos() const
|
||||
{
|
||||
MapStringString map;
|
||||
map[ID] = id();
|
||||
map[FPS] = QString::number(fps());
|
||||
map[RES] = QString::number(size().width()) + " * " + QString::number(size().height());
|
||||
return map;
|
||||
}
|
||||
|
||||
} // namespace video
|
||||
} // namespace lrc
|
||||
|
|
|
@ -36,9 +36,19 @@ class Renderer : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
constexpr static const char ID[] = "ID";
|
||||
constexpr static const char FPS[] = "FPS";
|
||||
constexpr static const char RES[] = "RES";
|
||||
constexpr static const int FPS_RATE_SEC = 1;
|
||||
|
||||
Renderer(const QString& id, const QSize& res);
|
||||
virtual ~Renderer();
|
||||
|
||||
/**
|
||||
* @return renderer's fps
|
||||
*/
|
||||
int fps() const;
|
||||
|
||||
/**
|
||||
* @return renderer's id
|
||||
*/
|
||||
|
@ -54,6 +64,13 @@ public:
|
|||
*/
|
||||
virtual lrc::api::video::Frame currentFrame() const = 0;
|
||||
|
||||
/**
|
||||
* set fps
|
||||
*/
|
||||
void setFPS(int fps);
|
||||
|
||||
MapStringString getInfos() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void startRendering() = 0;
|
||||
virtual void stopRendering() = 0;
|
||||
|
@ -63,10 +80,12 @@ Q_SIGNALS:
|
|||
void stopped();
|
||||
void started(const QSize& size);
|
||||
void frameBufferRequested(AVFrame* avFrame);
|
||||
void fpsChanged();
|
||||
|
||||
private:
|
||||
QString id_;
|
||||
QSize size_;
|
||||
int fps_;
|
||||
};
|
||||
|
||||
} // namespace video
|
||||
|
|
|
@ -90,10 +90,7 @@ public:
|
|||
, fpsC(0)
|
||||
, fps(0)
|
||||
, timer(new QTimer(this))
|
||||
#ifdef DEBUG_FPS
|
||||
, frameCount(0)
|
||||
, lastFrameDebug(std::chrono::system_clock::now())
|
||||
#endif
|
||||
{
|
||||
timer->setInterval(33);
|
||||
connect(timer, &QTimer::timeout, [this]() { Q_EMIT parent_->frameUpdated(); });
|
||||
|
@ -110,7 +107,6 @@ public:
|
|||
}
|
||||
|
||||
// Constants
|
||||
constexpr static const int FPS_RATE_SEC = 1;
|
||||
constexpr static const int FRAME_CHECK_RATE_HZ = 120;
|
||||
|
||||
// Lock the memory while the copy is being made
|
||||
|
@ -172,9 +168,10 @@ public:
|
|||
auto currentTime = std::chrono::system_clock::now();
|
||||
const std::chrono::duration<double> seconds = currentTime - lastFrameDebug;
|
||||
if (seconds.count() >= FPS_RATE_SEC) {
|
||||
fps = (int) (fpsC / seconds.count());
|
||||
fps = static_cast<int>(fpsC / seconds.count());
|
||||
fpsC = 0;
|
||||
lastFrameDebug = currentTime;
|
||||
parent_->setFPS(fps);
|
||||
#ifdef DEBUG_FPS
|
||||
qDebug() << this << ": FPS " << fps;
|
||||
#endif
|
||||
|
|
|
@ -1,178 +0,0 @@
|
|||
/****************************************************************************
|
||||
* Copyright (C) 2016-2022 Savoir-faire Linux Inc. *
|
||||
* Author: Olivier Grégoire <olivier.gregoire@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 "smartinfohub.h"
|
||||
#include "private/smartInfoHub_p.h"
|
||||
|
||||
#include <dbus/videomanager.h>
|
||||
#include <dbus/callmanager.h>
|
||||
#include <dbus/callmanager.h>
|
||||
|
||||
SmartInfoHub::SmartInfoHub()
|
||||
{
|
||||
d_ptr = new SmartInfoHubPrivate;
|
||||
connect(&CallManager::instance(),
|
||||
&CallManagerInterface::SmartInfo,
|
||||
this,
|
||||
&SmartInfoHub::slotSmartInfo,
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
SmartInfoHub::~SmartInfoHub() {}
|
||||
|
||||
void
|
||||
SmartInfoHub::start()
|
||||
{
|
||||
CallManager::instance().startSmartInfo(d_ptr->m_refreshTimeInformationMS);
|
||||
}
|
||||
|
||||
void
|
||||
SmartInfoHub::stop()
|
||||
{
|
||||
CallManager::instance().stopSmartInfo();
|
||||
}
|
||||
|
||||
SmartInfoHub&
|
||||
SmartInfoHub::instance()
|
||||
{
|
||||
// Singleton
|
||||
static SmartInfoHub instance_;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void
|
||||
SmartInfoHub::setRefreshTime(uint32_t timeMS)
|
||||
{
|
||||
d_ptr->m_refreshTimeInformationMS = timeMS;
|
||||
}
|
||||
|
||||
// Retrieve information from the map and implement all the variables
|
||||
void
|
||||
SmartInfoHub::slotSmartInfo(const MapStringString& map)
|
||||
{
|
||||
for (int i = 0; i < map.size(); i++)
|
||||
d_ptr->m_information[map.keys().at(i)] = map[map.keys().at(i)];
|
||||
|
||||
Q_EMIT changed();
|
||||
}
|
||||
// Getter
|
||||
|
||||
bool
|
||||
SmartInfoHub::isConference() const
|
||||
{
|
||||
return (d_ptr->m_information["type"] == "conference");
|
||||
}
|
||||
|
||||
float
|
||||
SmartInfoHub::localFps() const
|
||||
{
|
||||
if (!d_ptr->m_information[LOCAL_FPS].isEmpty())
|
||||
return d_ptr->m_information[LOCAL_FPS].toFloat();
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float
|
||||
SmartInfoHub::remoteFps() const
|
||||
{
|
||||
if (!d_ptr->m_information[REMOTE_FPS].isEmpty())
|
||||
return d_ptr->m_information[REMOTE_FPS].toFloat();
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
int
|
||||
SmartInfoHub::remoteWidth() const
|
||||
{
|
||||
if (!d_ptr->m_information[REMOTE_WIDTH].isEmpty())
|
||||
return d_ptr->m_information[REMOTE_WIDTH].toInt();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
SmartInfoHub::remoteHeight() const
|
||||
{
|
||||
if (!d_ptr->m_information[REMOTE_HEIGHT].isEmpty())
|
||||
return d_ptr->m_information[REMOTE_HEIGHT].toInt();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
SmartInfoHub::localWidth() const
|
||||
{
|
||||
if (!d_ptr->m_information[LOCAL_WIDTH].isEmpty())
|
||||
return d_ptr->m_information[LOCAL_WIDTH].toInt();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
SmartInfoHub::localHeight() const
|
||||
{
|
||||
if (!d_ptr->m_information[LOCAL_HEIGHT].isEmpty())
|
||||
return d_ptr->m_information[LOCAL_HEIGHT].toInt();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString
|
||||
SmartInfoHub::callID() const
|
||||
{
|
||||
if (!d_ptr->m_information[CALL_ID].isEmpty())
|
||||
return d_ptr->m_information[CALL_ID];
|
||||
else
|
||||
return SmartInfoHubPrivate::DEFAULT_RETURN_VALUE_QSTRING;
|
||||
}
|
||||
|
||||
QString
|
||||
SmartInfoHub::localVideoCodec() const
|
||||
{
|
||||
if (!d_ptr->m_information[LOCAL_VIDEO_CODEC].isEmpty())
|
||||
return d_ptr->m_information[LOCAL_VIDEO_CODEC];
|
||||
else
|
||||
return SmartInfoHubPrivate::DEFAULT_RETURN_VALUE_QSTRING;
|
||||
}
|
||||
|
||||
QString
|
||||
SmartInfoHub::localAudioCodec() const
|
||||
{
|
||||
if (!d_ptr->m_information[LOCAL_AUDIO_CODEC].isEmpty())
|
||||
return d_ptr->m_information[LOCAL_AUDIO_CODEC];
|
||||
else
|
||||
return SmartInfoHubPrivate::DEFAULT_RETURN_VALUE_QSTRING;
|
||||
}
|
||||
|
||||
QString
|
||||
SmartInfoHub::remoteVideoCodec() const
|
||||
{
|
||||
if (!d_ptr->m_information[REMOTE_VIDEO_CODEC].isEmpty())
|
||||
return d_ptr->m_information[REMOTE_VIDEO_CODEC];
|
||||
else
|
||||
return SmartInfoHubPrivate::DEFAULT_RETURN_VALUE_QSTRING;
|
||||
}
|
||||
|
||||
QString
|
||||
SmartInfoHub::remoteAudioCodec() const
|
||||
{
|
||||
if (!d_ptr->m_information[REMOTE_AUDIO_CODEC].isEmpty())
|
||||
return d_ptr->m_information[REMOTE_AUDIO_CODEC];
|
||||
else
|
||||
return SmartInfoHubPrivate::DEFAULT_RETURN_VALUE_QSTRING;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/****************************************************************************
|
||||
* Copyright (C) 2016-2022 Savoir-faire Linux Inc. *
|
||||
* Author: Olivier Grégoire <olivier.gregoire@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
|
||||
|
||||
#include <QObject>
|
||||
#include "typedefs.h"
|
||||
|
||||
class SmartInfoHubPrivate;
|
||||
|
||||
class SmartInfoHub final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
// Singleton
|
||||
static SmartInfoHub& instance();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
void setRefreshTime(uint32_t timeMS);
|
||||
|
||||
// Getter
|
||||
float localFps() const;
|
||||
float remoteFps() const;
|
||||
int remoteWidth() const;
|
||||
int remoteHeight() const;
|
||||
int localWidth() const;
|
||||
int localHeight() const;
|
||||
QString callID() const;
|
||||
QString localVideoCodec() const;
|
||||
QString localAudioCodec() const;
|
||||
QString remoteVideoCodec() const;
|
||||
QString remoteAudioCodec() const;
|
||||
bool isConference() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/// Emitted when informations have changed
|
||||
void changed();
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotSmartInfo(const MapStringString& info);
|
||||
|
||||
private:
|
||||
// use to initialise the connection between the Qsignal and the lambda function
|
||||
SmartInfoHub();
|
||||
virtual ~SmartInfoHub();
|
||||
|
||||
SmartInfoHubPrivate* d_ptr;
|
||||
};
|
Loading…
Add table
Reference in a new issue