Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Christian Ehrlicher, SLSE, 2016-02-29
#
#
# Data Plugin
#
SET(avm_SRCS
avm_data_plugin.cpp
avm_data_plugin.h
rt_profile_observer.cpp
rt_profile_observer.h
avs_session_context.cpp
avs_session_context.h
avm_exercise_context.cpp
avm_exercise_context.h
operator_settings_observer.cpp
operator_settings_observer.h
)
NGL_ADD_LIBRARY(WS AvmDataPlugin MODULE ${avm_SRCS})
NGL_TARGET_LINK_LIBRARIES(AvmDataPlugin
NGLLogger
ngltranslator
nglsettings
LtsSessionDataDds
LtsSession
LtsSessionData
AvmDataPluginInterface
svcAvmClient
AvmShared
svcOpmClient
svcExmClient
svcIsmClient
IsmDataPluginInterface
Qt5::Core
LtsUtilsGuiStyleManager
LtsUtilsGuiConnectDialog
LtsUtilsSettings
Boost::boost
)
NGL_INSTALL_TARGET(AvmDataPlugin)
+182
View File
@@ -0,0 +1,182 @@
/**
* @RDE_HEADER@
* Data Plugin for AudioVideoSystem
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-08-17
*/
#include "avm_data_plugin.h"
#include <AudioVideoManagement/Shared/plugin_settings.h>
#include <AudioVideoManagement/logger.h>
#include <AudioVideoManagement/ava_control.h>
#include <AudioVideoManagement/ava_session.h>
#include <AudioVideoManagement/ava_state.h>
#include <AudioVideoManagement/ava_types.h>
#include <AudioVideoManagement/stream_name_mapping.h>
#include <AudioVideoManagement/avs_menus.h>
#include <AudioVideoManagement/avs_dialog.h>
#include <AudioVideoManagement/vd_session.h>
#include <AudioVideoManagement/Shared/avs_app.h>
#include <AudioVideoManagement/stream_name_mapping.h>
#include <OperatorManagement/opm.hpp>
#include <QMap>
#include <QPair>
#include <QtGlobal>
#include <LtsSession/lts_session_data_dds.h>
#include <LtsSession/lts_session.h>
#include <LtsSession/lts_session_data.h>
#include <StyleManager/style_manager.h>
#include <ngltranslator/ngltranslator.h>
#include <QDebug>
using namespace AudioVideoManagement;
namespace
{
AvaGuiStyle determineGuiStyle()
{
LtsUtils::StyleManager *styleManager = LtsUtils::StyleManager::getInstance();
if (styleManager->currentStyleName() == QStringLiteral("rme.dark"))
return AvaGuiStyle::Dark;
return AvaGuiStyle::Light;
}
} // anonymous namespace
namespace AudioVideoManagement
{
DataPlugin::DataPlugin()
: m_pluginSettings(new PluginSettings)
{}
DataPlugin::~DataPlugin() = default;
std::shared_ptr<DataPluginBase::Interface> DataPlugin::createDataInterface(LtsSession::LtsSessionDataDds *session)
{
Q_ASSERT(session);
int exerciseId = session->exerciseId();
return std::make_shared<DataInterfaceImpl>(session, AvmExerciseContextHandle(&m_exerciseContext, exerciseId, session), &m_avsSessionContext);
}
DataInterfaceImpl::DataInterfaceImpl(LtsSession::LtsSessionDataDds *session, AvmExerciseContextHandle &&exerciseContextHandle, AvsSessionContext *sessionContext)
: m_exerciseContextHandle(std::move(exerciseContextHandle))
, m_session(qobject_cast<LtsSession::LtsSession *>(session))
{
Q_ASSERT(session);
Q_ASSERT(session->partitionType() == IDL::PartitionType::Exercise ||
session->partitionType() == IDL::PartitionType::Replay ||
session->partitionType() == IDL::PartitionType::Global);
Q_ASSERT(sessionContext);
if (session->exerciseId() > 0 && sessionContext->canAcquire(session->exerciseId()))
{
LtsSessionData::LtsSessionData *sessionData = LtsSessionData::LtsSessionData::getInstance();
m_avsSessionContextHandle = AvsSessionContextHandle(sessionContext, session->exerciseId(),
sessionData->getOperatorId(),
QString::fromLatin1(NGL::translationLocale()),
determineGuiStyle(), m_exerciseContextHandle);
}
}
DataInterfaceImpl::~DataInterfaceImpl() = default;
AvaSession *DataInterfaceImpl::avaSession()
{
return m_avsSessionContextHandle.avaSession();
}
AvaState *DataInterfaceImpl::avaState()
{
return m_avsSessionContextHandle.avaState();
}
StreamNameMapping *DataInterfaceImpl::streamNameMapping()
{
return m_exerciseContextHandle.streamNameMapping();
}
AvsMenus *DataInterfaceImpl::menus()
{
return m_avsSessionContextHandle.menus();
}
VdSession *DataInterfaceImpl::vdSession()
{
return m_avsSessionContextHandle.vdSession();
}
bool DataInterfaceImpl::vdSessionEstablished() const
{
return m_avsSessionContextHandle.vdSession()->isEstablished();
};
void DataInterfaceImpl::showCamera(QWidget *irreplacableWidget, int mountingPointId)
{
if (!m_avsSessionContextHandle)
return;
// build list of irreplacable widgets by the dependency tree of its dependencies and their dependencies' dependencies
QVector<QWidget *> irreplacableWidgets {m_session->baseLayoutWidget(), irreplacableWidget};
LtsSession::LtsSession *dependency = m_session->dependency();
int runaway = 100;
while (dependency && runaway > 0)
{
irreplacableWidgets += dependency->baseLayoutWidget();
dependency = dependency->dependency();
runaway--;
}
qWarning() << "irreplacableWidgets count" << irreplacableWidgets.count() << "from" << m_session;
for (QWidget *w : irreplacableWidgets)
qWarning() << "irre" << w;
m_avsSessionContextHandle.liveVideoApp()->show(irreplacableWidgets);
QString streamName = streamNameMapping()->internalName(mountingPointId);
m_avsSessionContextHandle.avaSession()->control()->chooseStreamOverview(AvsDialog::VIDEO_1, {streamName});
}
void DataInterfaceImpl::showAnnouncementUnit(int mountingPointId)
{
if (!m_avsSessionContextHandle)
return;
m_avsSessionContextHandle.menus()->setAnnouncementUnit(mountingPointId);
}
void DataInterfaceImpl::showOrCloseAvsApp()
{
if (!m_avsSessionContextHandle)
return;
auto liveVideoApp = m_avsSessionContextHandle.liveVideoApp();
qWarning() << "showOrCloseAvsApp" << liveVideoApp->isVisible();
if (liveVideoApp->isActive())
liveVideoApp->hide(true /* and close */);
else
liveVideoApp->show();
}
} // namespace AudioVideoManagement
+108
View File
@@ -0,0 +1,108 @@
/**
* @RDE_HEADER@
* HMI Plugin for AudioVideoSystem
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-08-17
*/
#pragma once
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
#include <AudioVideoManagement/avm_dtc.h>
#include <OperatorManagement/opm_dtc.h>
#include "avm_exercise_context.h"
#include "avs_session_context.h"
#include <memory>
namespace LtsSession { class LtsSession; }
namespace AudioVideoManagement
{
class AvaSession;
class AvaState;
class PlaybackApp;
class PluginSettings;
class StreamNameMapping;
class DataPlugin final : public QObject, public DataPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "data:3:avm")
Q_INTERFACES(DataPluginBase::Plugin)
Q_OBJECT
public:
DataPlugin();
~DataPlugin();
QString pluginName() const override { return QStringLiteral("AudioVideoManagement"); }
std::shared_ptr<DataPluginBase::Interface> createDataInterface(LtsSession::LtsSessionDataDds *session) override;
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Exercise || partition == IDL::PartitionType::Replay || partition == IDL::PartitionType::Global; }
private:
AvmExerciseContextManager m_exerciseContext;
AvsSessionContext m_avsSessionContext;
std::unique_ptr<PluginSettings> m_pluginSettings; //!< the singleton instance
};
class DataInterfaceImpl final : public DataInterface
{
public:
DataInterfaceImpl(LtsSession::LtsSessionDataDds *session, AvmExerciseContextHandle &&exerciseContextHandle, AvsSessionContext *sessionContext);
~DataInterfaceImpl();
std::shared_ptr<AudioVideoManagement::Interface::Dtc> getDtc() override { return m_exerciseContextHandle.dtc(); }
std::shared_ptr<AudioVideoManagement::Interface::Ftc> getFtc() override { return m_exerciseContextHandle.ftc(); }
ExerciseManagement::Interface::Dtc *getExmDtc() override { return m_exerciseContextHandle.exmDtc(); }
OperatorManagement::Interface::Dtc *getOpmDtc() override { return m_exerciseContextHandle.opmDtc(); }
/**
* @name Access to the communication session with AVS_Workstation and related parts.
* The getter-methods may only be called when hasAvsSession() returns true.
* They always return a valid pointer then.
*/
///@{
bool hasAvsSession() const override { return m_avsSessionContextHandle; }
bool vdSessionEstablished() const override;
AvaSession *avaSession() override;
AvaState *avaState() override;
AvsMenus *menus() override;
PlaybackApp *videoPlaybackApp() override { return m_avsSessionContextHandle.videoPlaybackApp(); }
PlaybackApp *audioPlaybackApp() override { return m_avsSessionContextHandle.audioPlaybackApp(); }
PlaybackApp *videoPresentationApp() override { return m_avsSessionContextHandle.videoPresentationApp(); }
PlaybackApp *audioPresentationApp() override { return m_avsSessionContextHandle.audioPresentationApp(); }
///@}
/**
* @name Access to the communication session with AVS_Export.
* The getter-methods may only be called when hasAvsSession() returns true.
* They always return a valid pointer then.
*/
///@{
VdSession *vdSession() override;
///@}
/** Only available when not in global partition; must not be called otherwise. */
StreamNameMapping *streamNameMapping() override;
/** No-op when hasAvsSession() == false. */
///{@
void showCamera(QWidget *irreplacableWidget, int mountingPointId) override;
void showAnnouncementUnit(int mountingPointId) override;
void showOrCloseAvsApp() override;
///@}
private:
AvmExerciseContextHandle m_exerciseContextHandle;
AvsSessionContextHandle m_avsSessionContextHandle;
LtsSession::LtsSession *m_session;
};
} // namespace AudioVideoManagement
@@ -0,0 +1,167 @@
/**
* @RDE_HEADER@
* AvmExerciseContext
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, NLSE, 2018-07-30
*/
#include "avm_exercise_context.h"
#include <AudioVideoManagement/stream_name_mapping.h>
#include <AudioVideoManagement/avm_dtc.h>
#include <AudioVideoManagement/avm_ftc.h>
#include <ExerciseManagement/exm_dtc.h>
#include <OperatorManagement/opm_dtc.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <LtsSession/lts_session_data_dds.h>
#include <ConnectDialog/connect_dialog_nt.h>
#include <QObject>
#include <QtGlobal>
#include <utility>
namespace AudioVideoManagement
{
/**
* Small composite that just holds all entities bound to the Exercise context.
*/
struct AvmExerciseContextManager::ExerciseContext
{
explicit ExerciseContext(LtsSession::LtsSessionDataDds *session)
{
static const int TIMEOUT_MS = 1000;
Q_ASSERT(session);
session->createTopicClient(dtc, ftc);
opmDtc = OperatorManagement::Interface::Dtc::create(session->ddsConnectorGlobal());
exmDtc = ExerciseManagement::Interface::Dtc::create(session->ddsConnectorGlobal());
ismDtc = InfrastructureManagement::Interface::Dtc::create(session->ddsConnectorGlobal());
if (session->exerciseId() > 0)
streamNameMapping.reset(StreamNameMapping::create(dtc.get()));
opmDtc->enableUser();
opmDtc->waitForHistoricalDataUser(TIMEOUT_MS); // TODO: FIXME: solange man hier keinen ConnectingDialogNT benutzen kann, kein Assert
exmDtc->enableExercise();
exmDtc->waitForHistoricalDataExercise(TIMEOUT_MS);
ismDtc->enableMountingPointAsset();
ismDtc->waitForHistoricalDataMountingPointAsset(TIMEOUT_MS);
dtc->enableCnrConfig();
dtc->enableTvcConfig();
dtc->enableCnrTvcProfile();
dtc->enableMenuStruct();
dtc->waitForHistoricalDataCnrConfig(TIMEOUT_MS);
dtc->waitForHistoricalDataTvcConfig(TIMEOUT_MS);
dtc->waitForHistoricalDataCnrTvcProfile(TIMEOUT_MS);
dtc->waitForHistoricalDataMenuStruct(TIMEOUT_MS);
}
std::shared_ptr<Interface::Dtc> dtc;
std::shared_ptr<Interface::Ftc> ftc;
std::shared_ptr<OperatorManagement::Interface::Dtc> opmDtc;
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc;
std::unique_ptr<StreamNameMapping> streamNameMapping;
};
AvmExerciseContextManager::RefCountedContext::RefCountedContext(std::unique_ptr<AvmExerciseContextManager::ExerciseContext> &&context)
: context(std::move(context))
{}
AvmExerciseContextManager::RefCountedContext::RefCountedContext(AvmExerciseContextManager::RefCountedContext &&) noexcept = default;
AvmExerciseContextManager::RefCountedContext::~RefCountedContext() = default;
AvmExerciseContextManager::~AvmExerciseContextManager()
{
// cfroebel 2018-07-31: Workaround for Bug REGG-4775
// All contexts should have been destroyed by now.
// But due to the bug there is one last context for Ex 0.
// Q_ASSERT(m_activeContexts.empty()); TODO: reactivate after fix
if (m_activeContexts.empty())
return;
Q_ASSERT(m_activeContexts.size() == 1);
//Q_ASSERT(m_activeContexts.begin()->first == 0); TODO: reactivate after fix
}
AvmExerciseContextManager::ExerciseContext *AvmExerciseContextManager::acquire(int exerciseId, LtsSession::LtsSessionDataDds *session)
{
auto found = m_activeContexts.find(exerciseId);
if (found != m_activeContexts.end())
{
++found->second.refCount;
return found->second.context.get();
}
std::unique_ptr<ExerciseContext> composite(new ExerciseContext(session));
auto insertResult = m_activeContexts.insert(std::make_pair(exerciseId, RefCountedContext(std::move(composite))));
Q_ASSERT(insertResult.second);
return insertResult.first->second.context.get();
}
void AvmExerciseContextManager::release(int exerciseId, AvmExerciseContextManager::ExerciseContext *composite)
{
auto found = m_activeContexts.find(exerciseId);
Q_ASSERT(found != m_activeContexts.end());
Q_ASSERT(found->second.context.get() == composite);
--found->second.refCount;
if (found->second.refCount == 0)
m_activeContexts.erase(found);
}
AvmExerciseContextHandle::AvmExerciseContextHandle() = default;
AvmExerciseContextHandle::AvmExerciseContextHandle(AvmExerciseContextManager *context, int exerciseId, LtsSession::LtsSessionDataDds *session)
: m_context(context->acquire(exerciseId, session), [exerciseId, context](AvmExerciseContextManager::ExerciseContext *composite) { context->release(exerciseId, composite); })
{
Q_ASSERT(context);
Q_ASSERT(m_context);
}
StreamNameMapping *AvmExerciseContextHandle::streamNameMapping() const
{
Q_ASSERT(m_context);
Q_ASSERT(m_context->streamNameMapping);
return m_context->streamNameMapping.get();
}
const std::shared_ptr<Interface::Dtc> &AvmExerciseContextHandle::dtc() const
{
Q_ASSERT(m_context);
return m_context->dtc;
}
const std::shared_ptr<Interface::Ftc> &AvmExerciseContextHandle::ftc() const
{
Q_ASSERT(m_context);
return m_context->ftc;
}
OperatorManagement::Interface::Dtc *AvmExerciseContextHandle::opmDtc() const
{
Q_ASSERT(m_context);
return m_context->opmDtc.get();
}
ExerciseManagement::Interface::Dtc *AvmExerciseContextHandle::exmDtc() const
{
Q_ASSERT(m_context);
return m_context->exmDtc.get();
}
InfrastructureManagement::Interface::Dtc *AvmExerciseContextHandle::ismDtc() const
{
Q_ASSERT(m_context);
return m_context->ismDtc.get();
}
} // namespace AudioVideoManagement
@@ -0,0 +1,161 @@
/**
* @RDE_HEADER@
* AvmExerciseContext
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, NLSE, 2018-07-30
*/
#pragma once
#include <map>
#include <functional>
#include <memory>
namespace LtsSession
{
class LtsSessionDataDds;
}
namespace OperatorManagement
{
namespace Interface
{
class Dtc;
}
}
namespace ExerciseManagement
{
namespace Interface
{
class Dtc;
}
}
namespace InfrastructureManagement
{
namespace Interface
{
class Dtc;
}
}
namespace AudioVideoManagement
{
namespace Interface
{
class Dtc;
class Ftc;
}
class StreamNameMapping;
/**
* For each Exercise -- as defined by its Id -- AvmExerciseContextManager manages
* an associated ExerciseContext. The ExerciseContext just holds all necessary entities.
* The idea is that any number of PluginInterface-instances with the same exerciseId
* share the same ExerciseContext.
* For example, all PluginInterface-instances for Exercise 42 can share the *same* Dtc or Ftc.
* Thus Dtc and Ftc are part of the ExerciseContext.
*
* The lifetime of an ExerciseContext can be longer than the lifetime of a PluginInterface-instance.
* AvsSessionContext uses (references) entities from the ExerciseContext.
* This is ok as it is guaranteed that the lifetime of the ExerciseContext is at least as long
* as the lifetime of AvsSessionContext.
* Actually they have the same lifetime -- if an AvsSessionContext exists.
*
* The difference is that there can be at most one AvsSessionContext at the same time.
* But there can be at most one ExerciseContext *for each* exerciseId at the same time.
* For the global exercise (exerciseId 0) there is never an AvsSessionContext.
*
* The following picuture illustrates the lifetimes:
*
* App1 (42) --------- ---------
* App2 (42) --------- ---------
* App3 (35) =========
*
* ExerciseContext (42) --------- --------------- ---------
* ExerciseContext (35) =========
*
* AvsSessionContext (42) --------- ---------------
* AvsSessionContext (35) =========
*
* PluginInterface-instance 1 (42) ---------
* PluginInterface-instance 2 (42) ---------
* PluginInterface-instance 3 (42) ---------
* PluginInterface-instance 4 (35) =========
* PluginInterface-instance 5 (42) ---------
*
* @see AvsSessionContext
* @author Christian Fröbel
*/
class AvmExerciseContextManager
{
public:
struct ExerciseContext;
~AvmExerciseContextManager();
/**
* Don't use directly; use AvmExerciseContextHandle instead.
*/
///@{
ExerciseContext *acquire(int exerciseId, LtsSession::LtsSessionDataDds *session);
void release(int exerciseId, ExerciseContext *composite);
///@}
private:
/**
* Small internal helper class in order to keep track of the refCount.
* Here, the refCount denotes the number of PluginInterface-Instances for the same Exercise.
*/
struct RefCountedContext
{
explicit RefCountedContext(std::unique_ptr<ExerciseContext> &&context);
RefCountedContext(RefCountedContext &&) noexcept;
~RefCountedContext();
int refCount{1};
std::unique_ptr<ExerciseContext> context;
};
using ExerciseId = int;
std::map<ExerciseId, RefCountedContext> m_activeContexts;
};
/**
* Helper class to automatically call AvmExerciseContextManager::acquire()
* and AvmExerciseContextManager::release() in the ctor and dtor respectively.
* Instances can be moved but not copied.
*
* @author Christian Fröbel
*/
class AvmExerciseContextHandle
{
public:
AvmExerciseContextHandle();
AvmExerciseContextHandle(AvmExerciseContextManager *context, int exerciseId, LtsSession::LtsSessionDataDds *session);
operator bool() const { return m_context.get(); }
/** Only available when not in global Exercise */
StreamNameMapping *streamNameMapping() const;
const std::shared_ptr<Interface::Dtc> &dtc() const;
const std::shared_ptr<Interface::Ftc> &ftc() const;
OperatorManagement::Interface::Dtc *opmDtc() const;
ExerciseManagement::Interface::Dtc *exmDtc() const;
InfrastructureManagement::Interface::Dtc *ismDtc() const;
private:
using Releaser = std::function<void (AvmExerciseContextManager::ExerciseContext *)>;
std::unique_ptr<AvmExerciseContextManager::ExerciseContext, Releaser> m_context;
};
} // namespace AudioVideoManagement
@@ -0,0 +1,193 @@
/**
* @RDE_HEADER@
* AvsSessionContext
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, SLSE, 2017-08-03
*/
#include "avs_session_context.h"
#include "avm_exercise_context.h"
#include "operator_settings_observer.h"
#include "rt_profile_observer.h"
#include <AudioVideoManagement/avs_menus.h>
#include <AudioVideoManagement/ava_comm.h>
#include <AudioVideoManagement/ava_control.h>
#include <AudioVideoManagement/ava_session.h>
#include <AudioVideoManagement/ava_state.h>
#include <AudioVideoManagement/vd_comm.h>
#include <AudioVideoManagement/vd_control.h>
#include <AudioVideoManagement/vd_session.h>
#include <AudioVideoManagement/avs_dialog.h>
#include <AudioVideoManagement/stream_name_mapping_to_ava.h>
#include <AudioVideoManagement/Shared/avs_app.h>
#include <AudioVideoManagement/Shared/playback_app.h>
#include <AudioVideoManagement/Shared/plugin_settings.h>
#include <OperatorManagement/opm_dtc.h>
#include <OperatorManagement/opm.hpp>
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/ism.hpp>
#include <nglsettings/nglsettings_connections.h>
#include <LtsUtilsSettings/settings.h>
#include <QObject>
#include <QtGlobal>
namespace AudioVideoManagement
{
/// AvsSessionContext
struct AvsSessionContext::Composite
{
Composite(int exerciseId_, int operatorId, const QString &langCode, AvaGuiStyle guiStyle, const AvmExerciseContextHandle &exerciseContextHandle)
: exerciseId(exerciseId_)
, operator_(exerciseContextHandle.opmDtc()->user(operatorId))
, audioPrioObserver(exerciseId_, operatorId, exerciseContextHandle.opmDtc(), exerciseContextHandle.exmDtc())
, avaComm(NGL::Connections::hostName(NGL::Connections::eConnection::AVS_WORKSTATION), NGL::Connections::port(NGL::Connections::eConnection::AVS_WORKSTATION))
, avaControl(&avaComm, exerciseContextHandle.streamNameMapping(), PluginSettings::instance()->avaTimeout())
, avaSession(&avaControl, exerciseId, QString::fromStdString(operator_.name()), langCode, operator_.audioChannelPriority(), audioPrioObserver.timezone(), guiStyle, PluginSettings::instance()->avaKeepAliveEnabled())
, avaState(&avaSession)
, streamNameMappingToAva(&avaSession, exerciseContextHandle.streamNameMapping())
, avsMenus(&avaSession, exerciseContextHandle.dtc().get(), exerciseContextHandle.ismDtc(), avaState.rtState())
, rtProfileObserver(exerciseContextHandle.dtc().get(), &avaSession, avaState.rtState(), exerciseId_, operatorId)
, vdComm(NGL::Connections::hostName(NGL::Connections::eConnection::AVS_WORKSTATION_VD), NGL::Connections::port(NGL::Connections::eConnection::AVS_WORKSTATION_VD))
, vdControl(&vdComm, PluginSettings::instance()->vdTimeout())
, vdSession(&vdControl, exerciseId, PluginSettings::instance()->vdKeepAliveEnabled())
, liveVideoApp(AvsDialog::VIDEO_1, &avaControl)
, videoPlaybackApp(AvsDialog::VIDEO_PLAYBACK, &avaControl, PlaybackApp::AppType::Normal)
, audioPlaybackApp(AvsDialog::AUDIO_PLAYBACK, &avaControl, PlaybackApp::AppType::AlwaysHidden)
, videoPresentationApp(AvsDialog::VIDEO_PRESENTATION, &avaControl, PlaybackApp::AppType::AutoHide)
, audioPresentationApp(AvsDialog::AUDIO_PRESENTATION, &avaControl, PlaybackApp::AppType::AlwaysHidden)
{
QObject::connect(&audioPrioObserver, &OperatorSettingsObserver::audioPrioChanged, &avaSession, &AvaSession::onAudioPrioChanged);
QObject::connect(&audioPrioObserver, &OperatorSettingsObserver::timezoneChanged, &avaSession, &AvaSession::onTimezoneChanged);
avaComm.start();
vdComm.start();
}
int exerciseId;
OperatorManagement::User operator_;
OperatorSettingsObserver audioPrioObserver;
AvaComm avaComm;
AvaControl avaControl;
AvaSession avaSession;
AvaState avaState;
StreamNameMappingToAva streamNameMappingToAva;
AvsMenus avsMenus;
RtProfileObserver rtProfileObserver;
VdComm vdComm;
VdControl vdControl;
VdSession vdSession;
AvsApp liveVideoApp;
PlaybackApp videoPlaybackApp;
PlaybackApp audioPlaybackApp;
PlaybackApp videoPresentationApp;
PlaybackApp audioPresentationApp;
};
AvsSessionContext::AvsSessionContext() = default;
AvsSessionContext::~AvsSessionContext()
{
//Q_ASSERT(m_refCount == 0);
}
bool AvsSessionContext::canAcquire(int exerciseId) const
{
Q_ASSERT(exerciseId > 0);
if (!m_composite)
return true;
return exerciseId == m_composite->exerciseId;
}
AvsSessionContext::Composite *AvsSessionContext::acquire(int exerciseId, int operatorId, const QString &langCode, AvaGuiStyle guiStyle, const AvmExerciseContextHandle &exerciseContextHandle)
{
Q_ASSERT(exerciseId > 0);
if (m_refCount == 0)
m_composite.reset(new Composite(exerciseId, operatorId, langCode, guiStyle, exerciseContextHandle));
else
Q_ASSERT(exerciseId == m_composite->exerciseId);
++m_refCount;
return m_composite.get();
}
void AvsSessionContext::release(Composite *composite)
{
Q_ASSERT(composite);
Q_ASSERT(composite == m_composite.get());
--m_refCount;
if (m_refCount == 0)
m_composite.reset();
}
/// AvsSessionContextHandle
AvsSessionContextHandle::AvsSessionContextHandle(/*LtsSession::LtsSession *session, */AvsSessionContext *context, int exerciseId, int operatorId, const QString &langCode, AvaGuiStyle guiStyle, const AvmExerciseContextHandle &exerciseContextHandle)
: m_composite(context->acquire(exerciseId, operatorId, langCode, guiStyle, exerciseContextHandle), [context](AvsSessionContext::Composite *composite) { context->release(composite); })
{
Q_ASSERT(context);
Q_ASSERT(m_composite);
}
AvaSession *AvsSessionContextHandle::avaSession() const
{
Q_ASSERT(m_composite);
return &m_composite->avaSession;
}
AvaState *AvsSessionContextHandle::avaState() const
{
Q_ASSERT(m_composite);
return &m_composite->avaState;
}
AvsMenus *AvsSessionContextHandle::menus() const
{
Q_ASSERT(m_composite);
return &m_composite->avsMenus;
}
VdSession *AvsSessionContextHandle::vdSession() const
{
Q_ASSERT(m_composite);
return &m_composite->vdSession;
}
AvsApp *AvsSessionContextHandle::liveVideoApp() const
{
Q_ASSERT(m_composite);
return &m_composite->liveVideoApp;
}
PlaybackApp *AvsSessionContextHandle::videoPlaybackApp() const
{
Q_ASSERT(m_composite);
return &m_composite->videoPlaybackApp;
}
PlaybackApp *AvsSessionContextHandle::audioPlaybackApp() const
{
Q_ASSERT(m_composite);
return &m_composite->audioPlaybackApp;
}
PlaybackApp *AvsSessionContextHandle::videoPresentationApp() const
{
Q_ASSERT(m_composite);
return &m_composite->videoPresentationApp;
}
PlaybackApp *AvsSessionContextHandle::audioPresentationApp() const
{
Q_ASSERT(m_composite);
return &m_composite->audioPresentationApp;
}
} // namespace AudioVideoManagement
+134
View File
@@ -0,0 +1,134 @@
/**
* @RDE_HEADER@
* AvsSessionContext
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, SLSE, 2017-08-03
*/
#pragma once
#include <AudioVideoManagement/ava_types.h>
#include <QString>
#include <memory>
#include <functional>
namespace OperatorManagement
{
namespace Interface
{
class Dtc;
}
}
namespace AudioVideoManagement
{
namespace Interface
{
class Dtc;
}
class AvaSession;
class AvaState;
class StreamNameMapping;
class AvsMenus;
class VdSession;
class AvmExerciseContextHandle;
class AvsApp;
class PlaybackApp;
/**
* AvsSessionContext ensures that there can only be one communication
* channel to AVS_Workstation and AVS_Export with a defined exercise context at
* any given time.
* AvsSessionContext must not be used with the global exercise (exerciseId 0).
*
* The application can have many users of the communication channels at the same time.
* The reason for this is that the AvmDataPlugin will be instantiated for every
* exercise (also live and replay) and possibly multiple times for an exercise.
* All these users shall share the same communication channels.
* But all parallel users must use the same exercise context.
*
* AvsSessionContext creates the communication channels (AvaSession, VdSession) when the first user
* calls acquire(). Subsequent users can get access to the same channels by also
* calling acquire() -- but the exercise context must match.
* When a user no longer needs these communication channels it calls release().
* When all users released the communication channels, they will be deleted.
* After that another user can call acquire() with a different exercise context.
*
* Use AvsSessionContextHandle to automatically acquire() and release()
* the communication channel.
*
* See AvmExerciseContext for a visualization of lifetimes of Apps, PluginInterface-instances
* and ExerciseContext.
*
* @see AvmExerciseContext
* @author Christian Fröbel
*/
class AvsSessionContext
{
public:
/**
* Small helper struct that holds all parts that make up a session.
* Only useful for AvsSessionContextHandle in order to access those parts.
*/
struct Composite;
AvsSessionContext();
~AvsSessionContext();
/**
* Check whether a AvsSessionContext with the given exerciseId can be acquired.
* Yields true when no AvsSessionContext was created yet or when the currently active
* AvsSessionContext is for the same exericse.
*/
bool canAcquire(int exerciseId) const;
/**
* Need not to be called directly; use AvsSessionContextHandle instead.
*/
///@{
Composite *acquire(int exerciseId, int operatorId, const QString &langCode, AvaGuiStyle, const AvmExerciseContextHandle &exerciseContextHandle);
void release(Composite *composite);
///@}
private:
std::unique_ptr<Composite> m_composite;
int m_refCount{0};
};
/**
* Helper class to automatically call AvsSessionContext::acquire()
* and AvsSessionContext::release() in the ctor and dtor respectively.
* Instances can be moved but not copied.
*/
class AvsSessionContextHandle
{
public:
AvsSessionContextHandle() = default;
AvsSessionContextHandle(AvsSessionContext *context, int exerciseId, int operatorId, const QString &langCode, AvaGuiStyle, const AvmExerciseContextHandle &exerciseContextHandle);
operator bool() const { return m_composite.get(); }
AvaSession *avaSession() const;
AvaState *avaState() const;
AvsMenus *menus() const;
VdSession *vdSession() const;
AvsApp *liveVideoApp() const;
PlaybackApp *videoPlaybackApp() const;
PlaybackApp *audioPlaybackApp() const;
PlaybackApp *videoPresentationApp() const;
PlaybackApp *audioPresentationApp() const;
private:
using Releaser = std::function<void (AvsSessionContext::Composite *)>;
std::unique_ptr<AvsSessionContext::Composite, Releaser> m_composite;
};
} // namespace AudioVideoManagement
@@ -0,0 +1,175 @@
/**
* @RDE_HEADER@
* OperatorSettingsObserver
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, NLSE, 2018-04-10
*/
#include "operator_settings_observer.h"
#include <LtsUtilsCore/data_modification_enum.h>
#include <LtsUtilsSettings/settings.h>
#include <ExerciseManagement/exm_dtc.h>
#include <ExerciseManagement/exm.hpp>
#include <OperatorManagement/opm_dtc.h>
#include <OperatorManagement/opm.hpp>
#include <QtGlobal>
namespace AudioVideoManagement
{
/**
* Small helper class that calculates the timezone for the current operator
* based on the operator's settings and the default timezone for the exercise.
*/
class OperatorSettingsObserver::TimezoneCalculator : public QObject
{
Q_OBJECT
public:
void setDefaultTimezone(QChar timezone)
{
Q_ASSERT(!timezone.isNull());
if (timezone == m_defaultTimezone)
return;
m_defaultTimezone = timezone;
calculateTimezone();
}
void setOperatorTimezone(QChar timezone)
{
Q_ASSERT(!timezone.isNull());
if (timezone == m_operatorTimezone)
return;
m_operatorTimezone = timezone;
calculateTimezone();
}
void unsetOperatorTimezone()
{
if (!m_operatorTimezone)
return;
m_operatorTimezone.reset();
calculateTimezone();
}
QChar timezone() const { return m_calculatedTimezone; }
signals:
void timezoneChanged(QChar newTimezone);
private:
void calculateTimezone()
{
QChar calculated = m_operatorTimezone.get_value_or(m_defaultTimezone);
if (calculated == m_calculatedTimezone)
return;
m_calculatedTimezone = calculated;
emit timezoneChanged(calculated);
}
QChar m_defaultTimezone = QLatin1Char('Z');
boost::optional<QChar> m_operatorTimezone;
QChar m_calculatedTimezone = m_defaultTimezone;
};
OperatorSettingsObserver::OperatorSettingsObserver(int exerciseId, int operatorId, OperatorManagement::Interface::Dtc *opmDtc, ExerciseManagement::Interface::Dtc *exmDtc)
: m_exerciseId(exerciseId)
, m_operatorId(operatorId)
, m_opmDtc(opmDtc)
, m_exmDtc(exmDtc)
, m_operatorSettings(LtsUtils::OperatorSettings::getInstance())
, m_timezoneCalculator(new TimezoneCalculator)
{
Q_ASSERT(operatorId > 0);
Q_ASSERT(opmDtc);
Q_ASSERT(exmDtc);
OperatorManagement::User operator_ = m_opmDtc->user(operatorId);
if (operator_.id() == operatorId)
m_currentPrio = operator_.audioChannelPriority();
ExerciseManagement::Exercise exercise = m_exmDtc->exercise(exerciseId);
if (exercise.id() == exerciseId)
m_timezoneCalculator->setDefaultTimezone(QChar::fromLatin1(exercise.defaultTimeZone()));
connect(opmDtc, &OperatorManagement::Interface::Dtc::userChanged, this, &OperatorSettingsObserver::onOperatorChanged);
connect(exmDtc, &ExerciseManagement::Interface::Dtc::exerciseChanged, this, &OperatorSettingsObserver::onExerciseChanged);
connect(m_operatorSettings, &LtsUtils::OperatorSettings::valueChanged, this, &OperatorSettingsObserver::onSettingsValueChanged);
connect(m_timezoneCalculator.get(), &TimezoneCalculator::timezoneChanged, this, &OperatorSettingsObserver::timezoneChanged); // signal -> signal
}
QChar OperatorSettingsObserver::timezone() const
{
return m_timezoneCalculator->timezone();
}
OperatorSettingsObserver::~OperatorSettingsObserver() = default;
void OperatorSettingsObserver::onOperatorChanged(const OperatorManagement::User &operator_, DataModification modType)
{
switch (modType)
{
case DataModification::eAdded:
return;
case DataModification::eModified:
{
if (operator_.id() != m_operatorId)
return;
AvaAudioPrio prio = operator_.audioChannelPriority();
if (prio == m_currentPrio)
return;
m_currentPrio = prio;
emit audioPrioChanged(prio);
return;
}
case DataModification::eRemoved:
return;
default:
Q_ASSERT(false);
}
}
void OperatorSettingsObserver::onExerciseChanged(const ExerciseManagement::Exercise &exercise, DataModification modType)
{
if (exercise.id() != m_exerciseId)
return;
switch (modType)
{
case DataModification::eModified:
m_timezoneCalculator->setDefaultTimezone(QChar::fromLatin1(exercise.defaultTimeZone()));
break;
default:
break;
}
}
void OperatorSettingsObserver::onSettingsValueChanged(const QString &group, const QString &identifier, const QVariant &value)
{
static const QString timeSettingsGroup = QStringLiteral("TimeSettings");
static const QString timezoneId = QStringLiteral("TimeZone");
if (group != timeSettingsGroup)
return;
if (identifier != timezoneId)
return;
QChar timezone = value.toChar();
if (timezone.isNull())
m_timezoneCalculator->unsetOperatorTimezone();
else
m_timezoneCalculator->setOperatorTimezone(timezone);
}
} // namespace AudioVideoManagement
#include "operator_settings_observer.moc"
@@ -0,0 +1,94 @@
/**
* @RDE_HEADER@
* OperatorSettingsObserver
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, NLSE, 2018-04-10
*/
#pragma once
#include <AudioVideoManagement/ava_types.h>
#include <boost/optional.hpp>
#include <QChar>
#include <QObject>
#include <memory>
namespace OperatorManagement
{
namespace Interface
{
class Dtc;
}
class User;
} // namespace OperatorManagement
namespace ExerciseManagement
{
namespace Interface
{
class Dtc;
}
class Exercise;
} // namespace ExerciseManagement
namespace LtsUtils
{
class OperatorSettings;
}
enum class DataModification;
namespace AudioVideoManagement
{
/**
* Small helper class to observe the following parts of the Operator's settings:
* - audio priority
* - timezone
*
* @author Christian Fröbel
*/
class OperatorSettingsObserver : public QObject
{
Q_OBJECT
public:
OperatorSettingsObserver(int exerciseId, int operatorId, OperatorManagement::Interface::Dtc *opmDtc, ExerciseManagement::Interface::Dtc *exmDtc);
~OperatorSettingsObserver();
QChar timezone() const;
signals:
void audioPrioChanged(AvaAudioPrio newPrio);
void timezoneChanged(QChar newTimezone);
private slots:
void onOperatorChanged(const OperatorManagement::User &operator_, DataModification modType);
void onExerciseChanged(const ExerciseManagement::Exercise &exercise, DataModification modType);
void onSettingsValueChanged(const QString &group, const QString &identifier, const QVariant &value);
private:
class TimezoneCalculator;
int m_exerciseId;
int m_operatorId;
OperatorManagement::Interface::Dtc *m_opmDtc;
ExerciseManagement::Interface::Dtc *m_exmDtc;
LtsUtils::OperatorSettings *m_operatorSettings;
std::unique_ptr<TimezoneCalculator> m_timezoneCalculator;
boost::optional<AvaAudioPrio> m_currentPrio;
};
} // namespace AudioVideoManagement
@@ -0,0 +1,156 @@
/**
* @RDE_HEADER@
* RtProfileObserver
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-08-17
*/
#include "rt_profile_observer.h"
#include <AudioVideoManagement/ava_session.h>
#include <AudioVideoManagement/ava_control.h>
#include <AudioVideoManagement/avm_dtc.h>
#include <LtsUtilsCore/data_modification_enum.h>
#include <QMap>
namespace AudioVideoManagement
{
RtProfileObserver::RtProfileObserver(Interface::Dtc *dtc, AvaSession *avaSession, RtState *rtState, int exerciseId, int operatorId)
: m_exerciseId(exerciseId)
, m_operatorId(operatorId)
, m_dtc(dtc)
, m_avaSession(avaSession)
, m_avaControl(avaSession->control())
, m_rtState(rtState)
{
Q_ASSERT(dtc);
Q_ASSERT(avaSession);
Q_ASSERT(rtState);
connect(m_avaSession, &AvaSession::sessionEstablished, this, &RtProfileObserver::onSessionEstablished);
connect(m_dtc, &Interface::Dtc::tvcConfigChanged, this, &RtProfileObserver::onTvcConfigChanged);
connect(m_dtc, &Interface::Dtc::cnrConfigChanged, this, &RtProfileObserver::onCnrConfigChanged);
connect(m_dtc, &Interface::Dtc::cnrTvcProfileChanged, this, &RtProfileObserver::onCnrTvcProfileChanged);
m_profile = getProfile();
if (m_avaSession->isEstablished())
onSessionEstablished();
}
void RtProfileObserver::onSessionEstablished()
{
loadVoiceRadioCommunicationMenu();
}
void RtProfileObserver::loadVoiceRadioCommunicationMenu()
{
m_avaControl->setRtProfile(m_rtState, defaultRtChannels());
}
void RtProfileObserver::onCnrConfigChanged(const CnrConfig &cnrConfig, DataModification modType)
{
if (modType != DataModification::eModified)
return;
if (!isInProfile(cnrConfig))
return;
m_avaControl->changeRtProfileCircuitName(m_rtState, {RadioSystem::Cnr, cnrConfig.id(), cnrConfig.radioCircuit()});
}
void RtProfileObserver::onTvcConfigChanged(const TvcConfig &tvcConfig, DataModification modType)
{
if (modType != DataModification::eModified)
return;
if (!isInProfile(tvcConfig))
return;
m_avaControl->changeRtProfileCircuitName(m_rtState, {RadioSystem::Tvc, tvcConfig.id(), tvcConfig.radioCircuit()});
}
void RtProfileObserver::onCnrTvcProfileChanged(const CnrTvcProfile &profile, DataModification modType)
{
Q_UNUSED(modType);
if (profile.exerciseId() != m_exerciseId || profile.operatorId() != m_operatorId)
return;
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
m_profile = profile;
break;
case DataModification::eRemoved:
m_profile.reset();
break;
default:
Q_ASSERT(false);
}
loadVoiceRadioCommunicationMenu();
}
QVector<RtState::RadioCircuit> RtProfileObserver::defaultRtChannels() const
{
if (!m_profile)
return {};
const QMap<int, CnrConfig> cnrcs = m_dtc->cnrConfigs();
const QMap<int, TvcConfig> tvccs = m_dtc->tvcConfigs();
QVector<RtState::RadioCircuit> rtChannels;
rtChannels.reserve(m_profile->data().size());
for (const auto &cnrTvcProfileData : m_profile->data())
{
std::string circuitName;
if (cnrTvcProfileData.radioSystemId() == RadioSystem::Cnr)
circuitName = cnrcs.value(cnrTvcProfileData.radioCircuitId()).radioCircuit();
else
circuitName = tvccs.value(cnrTvcProfileData.radioCircuitId()).radioCircuit();
rtChannels.push_back({cnrTvcProfileData.radioSystemId(), cnrTvcProfileData.radioCircuitId(), circuitName});
}
return rtChannels;
}
boost::optional<CnrTvcProfile> RtProfileObserver::getProfile() const
{
boost::optional<CnrTvcProfile> foundProfile;
std::function<bool(const CnrTvcProfile &profile)> forUserInExercise = [this, &foundProfile] (const CnrTvcProfile &profile)
{
if (profile.exerciseId() != m_exerciseId || profile.operatorId() != m_operatorId)
return false;
foundProfile = profile;
return true;
};
m_dtc->cnrTvcProfiles(forUserInExercise);
return foundProfile;
}
bool RtProfileObserver::isInProfile(const CnrConfig &cnrConfig) const
{
return isInProfile(RadioSystem::Cnr, cnrConfig.id());
}
bool RtProfileObserver::isInProfile(const TvcConfig &tvcConfig) const
{
return isInProfile(RadioSystem::Tvc, tvcConfig.id());
}
bool RtProfileObserver::isInProfile(RadioSystem radioSystem, int32_t id) const
{
if (!m_profile)
return false;
for (const auto &cnrTvcProfileData : m_profile->data())
if (cnrTvcProfileData.radioSystemId() == radioSystem && cnrTvcProfileData.radioCircuitId() == id)
return true;
return false;
}
} //namespace AudioVideoManagement
@@ -0,0 +1,66 @@
/**
* @RDE_HEADER@
* RtProfileObserver
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-08-17
*/
#pragma once
#include <AudioVideoManagement/ava_types.h>
#include <AudioVideoManagement/rt_state.h>
#include <AudioVideoManagement/avm.hpp>
#include <QObject>
#include <QVector>
#include <boost/optional.hpp>
enum class DataModification;
namespace AudioVideoManagement
{
namespace Interface
{
class Dtc;
}
class AvaSession;
class AvaControl;
class TvcConfig;
class CnrConfig;
class CnrTvcProfile;
class RtProfileObserver : public QObject
{
Q_OBJECT
public:
RtProfileObserver(Interface::Dtc *dtc, AvaSession *avaSession, RtState *rtState, int exerciseId, int operatorId);
private slots:
void onSessionEstablished();
void onTvcConfigChanged(const TvcConfig &tvcConfig, DataModification modType);
void onCnrConfigChanged(const CnrConfig &cnrConfig, DataModification modType);
void onCnrTvcProfileChanged(const CnrTvcProfile &profile, DataModification modType);
private:
void loadVoiceRadioCommunicationMenu();
QVector<RtState::RadioCircuit> defaultRtChannels() const;
boost::optional<CnrTvcProfile> getProfile() const;
bool isInProfile(const CnrConfig &cnrConfig) const;
bool isInProfile(const TvcConfig &tvcConfig) const;
bool isInProfile(RadioSystem radioSystem, int32_t id) const;
const int m_exerciseId;
const int m_operatorId;
boost::optional<CnrTvcProfile> m_profile;
Interface::Dtc *m_dtc;
AvaSession *m_avaSession;
AvaControl *m_avaControl;
RtState *m_rtState;
};
} //namespace AudioVideoManagement