314 lines
13 KiB
C++
Executable File
314 lines
13 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* AvaControl
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Christian Fröbel, SLSE, 2017-06-26
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "iava_command_done_observer.h"
|
|
#include "avm_export.h"
|
|
#include "ava_types.h"
|
|
#include "rt_state.h"
|
|
#include "avs_command_queue.h"
|
|
#include "logger.h"
|
|
#include <LtsUtilsCore/connection.h>
|
|
#include <QString>
|
|
#include <QVector>
|
|
#include <QObject>
|
|
#include <chrono>
|
|
|
|
class QStringList;
|
|
|
|
namespace AudioVideoManagement
|
|
{
|
|
|
|
class IAvaComm;
|
|
class ICommand;
|
|
class StreamNameMapping;
|
|
|
|
namespace AvaCommands
|
|
{
|
|
|
|
class ChooseStream;
|
|
class GetStreamList;
|
|
class QueryTimeline;
|
|
class GetElokaList;
|
|
class QueryEloka;
|
|
class SetAnnouncementProfile;
|
|
class SetVideoProfile;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* AvaControl sits ontop of AvaComm.
|
|
* For the communication with the AVS that must be exactly one AvaComm
|
|
* and one AvaControl instance.
|
|
* AvaControl uses a command queue and ensures that each command is sent after
|
|
* the previous command finished.
|
|
* The definition of when a command is finished is defined by the command itself.
|
|
* Most of the commands are SimpleCommands which only wait for the OK-response.
|
|
*
|
|
* For those commands that have a data-response -- such as getStreamList --
|
|
* a signal is provided that will be emitted when the command finished.
|
|
*
|
|
* Commands being sent while no connection is established will be dropped.
|
|
* When the connection gets lost, all Commands still in the queue will be dropped.
|
|
* When a command fails, all remaining commands will be dropped and the connection
|
|
* to the AVS will be closed and established again.
|
|
*
|
|
* A command must complete within a defined time frame. If it does not,
|
|
* the command is considered failed with the implications described above.
|
|
*
|
|
* There are two ways to get responses that contain data -- such as the result of
|
|
* getStreamList or queryTimeline:
|
|
* 1. Connect to the corresponding signals in the usual way. The problem with this
|
|
* approach arises when there are several clients using the AvaControl-instance
|
|
* at the same time. Then you receive all responses no matter who
|
|
* initiated the corresponding command.
|
|
* 2. You can specify an optional slot when issuing the command.
|
|
* This slot will be called when the command is finished. This way you only receive
|
|
* responses that correspond to the command you initiated.
|
|
*
|
|
* @see AvaComm
|
|
* @see AvaSession
|
|
* @see ICommand
|
|
* @author Christian Fröbel
|
|
*/
|
|
class AVM_COMMON_EXPORT AvaControl : public QObject, public IAvaCommandDoneObserver
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
AvaControl(IAvaComm *comm, StreamNameMapping *streamNameMapping, std::chrono::milliseconds commandTimeout);
|
|
|
|
void switchContext(int exerciseId);
|
|
void setUserProfile(const QString &userName, const QString &langCode, AvaAudioPrio, AvaGuiStyle);
|
|
void setTimezone(QChar tz);
|
|
void setVideoDialogProfile(const QString &dialogId, AvaVisibility);
|
|
void setVideoDialogGeometry(const QString &dialogId, const QRect &geometry);
|
|
template<class Target, class Slot>
|
|
void setVideoProfile(const QString &dialogId, const QString &menuDef, Target *target, Slot Target:: *slot);
|
|
void setVideoProfile(const QString &dialogId, const QString &menuDef);
|
|
template<class Target, class Slot>
|
|
void setRtProfile(RtState *rtState, const QVector<RtState::RadioCircuit> &radioCircuits, Target *target, Slot Target:: *slot);
|
|
void setRtProfile(RtState *rtState, const QVector<RtState::RadioCircuit> &radioCircuits);
|
|
template<class Target, class Slot>
|
|
void changeRtProfileCircuitName(RtState *rtState, const RtState::RadioCircuit &radioCircuit, Target *target, Slot Target:: *slot);
|
|
void changeRtProfileCircuitName(RtState *rtState, const RtState::RadioCircuit &radioCircuit);
|
|
template<class Target, class Slot>
|
|
void setAnnouncementProfile(RtState *rtState, const QString &menuDef, const QString &identityList, const QString &stateList, Target *target, Slot Target:: *slot);
|
|
void setAnnouncementProfile(RtState *rtState, const QString &menuDef, const QString &identityList, const QString &stateList);
|
|
void chooseImport(const QString &dialogId, const QString &path, int mode);
|
|
void releaseImport(const QString &dialogId);
|
|
|
|
|
|
/**
|
|
* @param slot must be a pointer to a method of Target and must be compatible with
|
|
* the getStreamListResponse()-signal.
|
|
*/
|
|
template<class Target, class Slot>
|
|
void getStreamList(AvaStreamType, AvaStreamSource, Target *target, Slot Target:: *slot);
|
|
void getStreamList(AvaStreamType, AvaStreamSource);
|
|
|
|
void chooseStream(const QString &dialogId, const QString &streamName);
|
|
void chooseStreamOverview(const QString &dialogId, const QStringList &streamNames);
|
|
void releaseStream(const QString &dialogId, const QString &streamName);
|
|
|
|
/**
|
|
* @param slot must be a pointer to a method of Target and must be compatible with
|
|
* the queryTimelineResponse()-signal.
|
|
*/
|
|
template<class Target, class Slot>
|
|
void queryTimeline(const QString &streamName, Target *target, Slot Target:: *slot, const boost::optional<AvaTimePoint> &start = {}, const boost::optional<AvaTimePoint> &end = {});
|
|
void queryTimeline(const QString &streamName, const boost::optional<AvaTimePoint> &start = {}, const boost::optional<AvaTimePoint> &end = {});
|
|
|
|
void setVolume(int db);
|
|
|
|
/** streamControl */
|
|
///@{
|
|
void startStream(const QString &dialogId, const QString &streamName, AvaSpeed);
|
|
void stopStream(const QString &dialogId, const QString &streamName);
|
|
void pauseStream(const QString &dialogId, const QString &streamName);
|
|
void setStreamSpeed(const QString &dialogId, const QString &streamName, AvaSpeed);
|
|
void setAbsPosition(const QString &dialogId, const QString &streamName, AvaTimePoint pos);
|
|
void positionUpdate(const QString &dialogId, const QString &streamName, std::chrono::milliseconds updateInterval);
|
|
void setPint(const QString &dialogId, const QString &streamName, bool doSkip);
|
|
///@}
|
|
|
|
/** ELOKA */
|
|
///@{
|
|
/**
|
|
* @param slot must be a pointer to a method of Target and must be compatible with
|
|
* the getElokaListResponse()-signal.
|
|
*/
|
|
template<class Target, class Slot>
|
|
void getElokaList(const QString &streamName, Target *target, Slot Target:: *slot);
|
|
void getElokaList(const QString &streamName);
|
|
void chooseEloka(const QString &streamName, const QString &signalName, AvaElokaMode mode);
|
|
void releaseEloka(const QString &streamName);
|
|
template<class Target, class Slot>
|
|
void queryEloka(AvaQueryElokaMode mode, Target *target, Slot Target:: *slot);
|
|
void queryEloka(AvaQueryElokaMode mode);
|
|
///@}
|
|
|
|
/** SCRIPT */
|
|
///@{
|
|
void setScript(const QString &dialogId, const QString &scriptName, AvaScriptSource,
|
|
const QVector<AvaScriptEntry> &streams, LtsUtils::IConnection *connection = nullptr);
|
|
void startScript(const QString &dialogId, const QString &scriptName, LtsUtils::IConnection *connection = nullptr);
|
|
void releaseScript(const QString &dialogId, const QString &scriptName);
|
|
///@}
|
|
|
|
/** scriptControl */
|
|
///@{
|
|
void stopScript(const QString &dialogId, const QString &scriptName);
|
|
void pauseScript(const QString &dialogId, const QString &scriptName);
|
|
void setAbsPositionScript(const QString &dialogId, const QString &scriptName, AvaTimePoint pos);
|
|
///@}
|
|
|
|
/** StreamNameMapping */
|
|
///@{
|
|
void defineStreamNameMapping(const QString &internalName, const QString &displayName);
|
|
void resetStreamNameMapping();
|
|
///@}
|
|
|
|
void keepAlive();
|
|
|
|
/**
|
|
* These overloaded done() methods will be called by the specific
|
|
* commands themselves upon completion.
|
|
*/
|
|
///@{
|
|
void done(ICommand *cmd) override;
|
|
void done(AvaCommands::ChooseStream *cmd) override;
|
|
void done(AvaCommands::GetStreamList *cmd) override;
|
|
void done(AvaCommands::QueryTimeline *cmd) override;
|
|
void done(AvaCommands::GetElokaList *cmd) override;
|
|
void done(AvaCommands::QueryEloka *cmd) override;
|
|
void done(AvaCommands::SetRtProfileBase *cmd) override;
|
|
void done(AvaCommands::SetAnnouncementProfile *cmd) override;
|
|
void done(AvaCommands::SetVideoProfile *cmd) override;
|
|
void done(AvaCommands::SetScript *cmd) override;
|
|
void done(AvaCommands::StartScript *cmd) override;
|
|
|
|
/**
|
|
* Called whenever a command fails due error response or other unexpected responses.
|
|
* All queued commands will be dropped and the connection to AVS will
|
|
* be disconnected and re-established.
|
|
*/
|
|
void failed(AvaCommands::SetScript *cmd);
|
|
void failed(ICommand *cmd) override;
|
|
///@}
|
|
|
|
void alive(ICommand *cmd) override;
|
|
|
|
/**
|
|
* Access to the underlying AvaComm-instance.
|
|
* @return never nullptr
|
|
*/
|
|
IAvaComm *comm() { return m_comm; }
|
|
|
|
bool isEmpty() const { return m_queue.isEmpty(); }
|
|
|
|
signals:
|
|
void chooseStreamResponse(const AvaStreamInfo &streamInfo, AvaStreamState);
|
|
void getStreamListResponse(const QVector<AvaStream> &streams);
|
|
void queryTimelineResponse(const AvaTimeline &timeline);
|
|
void getElokaListResponse(const QVector<QString> &elokaSignals);
|
|
void queryElokaResponse(const QVector<AvaEloka> &eloka);
|
|
void setRtProfileResponse(const QVector<QString> &invalidNameList);
|
|
void setAnnouncementProfileResponse(const QVector<QString> &invalidNameList);
|
|
void setVideoProfileResponse(const QVector<QString> &invalidNameList);
|
|
void setScriptResponse(const AvaStreamInfo &scriptInfo, AvaStreamState ScriptState);
|
|
void startScriptResponse( AvaStreamState ScriptState);
|
|
|
|
/**
|
|
* Signalled whenever the command queue is empty again. This can have several reasons:
|
|
* - The last command finished successfully.
|
|
* - A command failed and the command queue was flushed.
|
|
* - This instance is deleted with a non-empty command queue which gets flushed then.
|
|
*/
|
|
void commandQueueEmpty();
|
|
|
|
private slots:
|
|
void onConnected();
|
|
void onDisconnected();
|
|
void onTimeout();
|
|
|
|
private:
|
|
void getStreamList(AvaStreamType, AvaStreamSource, LtsUtils::IConnection *connection);
|
|
void queryTimeline(const QString &streamName, LtsUtils::IConnection *connection, const boost::optional<AvaTimePoint> &start = {}, const boost::optional<AvaTimePoint> &end = {});
|
|
void getElokaList(const QString &streamName, LtsUtils::IConnection *connection);
|
|
void queryEloka(AvaQueryElokaMode mode, LtsUtils::IConnection *connection);
|
|
void setRtProfile(RtState *rtState, const QVector<RtState::RadioCircuit> &radioCircuits, LtsUtils::IConnection *connection);
|
|
void changeRtProfileCircuitName(RtState *rtState, const RtState::RadioCircuit &radioCircuit, LtsUtils::IConnection *connection);
|
|
void setAnnouncementProfile(RtState *rtState, const QString &menuDef, const QString &identityList,
|
|
const QString &stateList, LtsUtils::IConnection *connection);
|
|
void setVideoProfile(const QString &dialogId, const QString &menuDef, LtsUtils::IConnection *connection);
|
|
|
|
|
|
void queue(ICommand *cmd, LtsUtils::IConnection *connection = nullptr);
|
|
|
|
IAvaComm *m_comm;
|
|
StreamNameMapping *m_streamNameMapping;
|
|
bool m_connected{false};
|
|
AvsCommandQueue m_queue;
|
|
LOGGER_T m_logger;
|
|
};
|
|
|
|
template<class Target, class Slot>
|
|
void AvaControl::getStreamList(AvaStreamType streamType, AvaStreamSource streamSource, Target *target, Slot Target:: *slot)
|
|
{
|
|
getStreamList(streamType, streamSource, LtsUtils::createConnection(this, &AvaControl::getStreamListResponse, target, slot));
|
|
}
|
|
|
|
template<class Target, class Slot>
|
|
void AvaControl::queryTimeline(const QString &streamName, Target *target, Slot Target:: *slot, const boost::optional<AvaTimePoint> &start, const boost::optional<AvaTimePoint> &end)
|
|
{
|
|
queryTimeline(streamName, LtsUtils::createConnection(this, &AvaControl::queryTimelineResponse, target, slot), start, end);
|
|
}
|
|
|
|
template<class Target, class Slot>
|
|
void AvaControl::getElokaList(const QString &streamName, Target *target, Slot Target:: *slot)
|
|
{
|
|
getElokaList(streamName, LtsUtils::createConnection(this, &AvaControl::getElokaListResponse, target, slot));
|
|
}
|
|
|
|
template<class Target, class Slot>
|
|
void AvaControl::queryEloka(AvaQueryElokaMode mode, Target *target, Slot Target:: *slot)
|
|
{
|
|
Q_ASSERT(mode != AvaQueryElokaMode::Stop);
|
|
queryEloka(mode, LtsUtils::createConnection(this, &AvaControl::queryElokaResponse, target, slot));
|
|
}
|
|
|
|
template<class Target, class Slot>
|
|
void AvaControl::setVideoProfile(const QString &dialogId, const QString &menuDef, Target *target, Slot Target:: *slot)
|
|
{
|
|
setVideoProfile(dialogId, menuDef, LtsUtils::createConnection(this, &AvaControl::setVideoProfileResponse, target, slot));
|
|
}
|
|
|
|
template<class Target, class Slot>
|
|
void AvaControl::setRtProfile(RtState *rtState, const QVector<RtState::RadioCircuit> &radioCircuits, Target *target, Slot Target:: *slot)
|
|
{
|
|
setRtProfile(rtState, radioCircuits, LtsUtils::createConnection(this, &AvaControl::setRtProfileResponse, target, slot));
|
|
}
|
|
|
|
template<class Target, class Slot>
|
|
void AvaControl::changeRtProfileCircuitName(RtState *rtState, const RtState::RadioCircuit &radioCircuit, Target *target, Slot Target:: *slot)
|
|
{
|
|
changeRtProfileCircuitName(rtState, radioCircuit, LtsUtils::createConnection(this, &AvaControl::setRtProfileResponse, target, slot));
|
|
}
|
|
|
|
template<class Target, class Slot>
|
|
void AvaControl::setAnnouncementProfile(RtState *rtState, const QString &menuDef, const QString &identityList, const QString &stateList, Target *target, Slot Target:: *slot)
|
|
{
|
|
setAnnouncementProfile(rtState, menuDef, identityList, stateList, LtsUtils::createConnection(this, &AvaControl::setAnnouncementProfileResponse, target, slot));
|
|
}
|
|
|
|
} // namespace AudioVideoManagement
|