354 lines
16 KiB
C++
354 lines
16 KiB
C++
/*
|
|
* To change this license header, choose License Headers in Project Properties.
|
|
* To change this template file, choose Tools | Templates
|
|
* and open the template in the editor.
|
|
*/
|
|
|
|
/*
|
|
* File: SPIT_Client.h
|
|
* Author: Hagi
|
|
*
|
|
* Created on 7. April 2019, 08:50
|
|
*/
|
|
|
|
#ifndef SPIT_CLIENT_H
|
|
#define SPIT_CLIENT_H
|
|
|
|
#include "SAD_DetectedServer.hpp"
|
|
#include "SPITObject.h"
|
|
#include "SPITPlayer.h"
|
|
#include "SPITSocket.h"
|
|
#include "SPITType.h"
|
|
#include "SPIT_Message.h"
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
using namespace std;
|
|
|
|
class SPIT_Client : I_SAD_Client {
|
|
|
|
public:
|
|
/** Maximal length of a SPITMessage*/
|
|
static const int MAXSPITMESSAGEBYTECOUNT = 512;
|
|
|
|
enum class ProjUpdate {
|
|
ServerLoaded,
|
|
StartTransfer,
|
|
EndTransfer,
|
|
ServerClosed,
|
|
};
|
|
enum class ServerEvent {
|
|
Detect,
|
|
Lost,
|
|
Changed,
|
|
};
|
|
enum class ObjectEvent {
|
|
Created,
|
|
Changed,
|
|
Deleted
|
|
};
|
|
|
|
struct Callbacks {
|
|
void (*onServerEvent)(ServerEvent event, const SAD_DetectedServer &p_DetectedServer){};
|
|
void (*onConnectionStatus)(string p_ServerID, string p_ServerComputerName, string p_ServerName, int p_ServerStepTime, int p_ConnectionStatus, int p_OldConnectionStatus){};
|
|
void (*onProjectUpdate)(ProjUpdate state, string projectId){};
|
|
|
|
void (*onSpitType)(ObjectEvent event, const SPITType &p_SPITType){};
|
|
void (*onSpitTypeRemote)(ObjectEvent event, const SPITType &p_SPITType){};
|
|
void (*onSpitObject)(ObjectEvent event, const SPITType &p_SPITType, const SPITObject &p_SPITObject){};
|
|
void (*onSpitObjectRemote)(ObjectEvent event, const SPITType &p_SPITType, const SPITObject &p_SPITObject){};
|
|
|
|
void (*onPlay)(string p_PlayerID, string p_PlayerName, char p_PlayerType, bool p_PlayerIsRunning, long long p_TimeFrames){};
|
|
void (*onPlaySpitType)(string p_PlayerID, string p_SPITTypeID, bool p_PlayerIsRunning, bool p_Started, bool p_Ended, double p_Value){};
|
|
void (*onPlayRemoteObjectStatus)(const SPITType &p_SPITType, const SPITObject &p_SPITObject, long long p_FrameInsideObject, int p_Value){};
|
|
bool (*onCheckSpitTypeVeto)(SPIT_Message::ReportSPITType *p_ReportSPITType){};
|
|
bool (*onCheckSpitObjectVeto)(SPIT_Message::ReportSPITObject *p_ReportSPITObject){};
|
|
};
|
|
|
|
//----- Connection Status -----
|
|
public:
|
|
/** No Connection established.<br>Either no connect tried or disconnected*/
|
|
static constexpr int CONNECTION_NONE = 0;
|
|
/** Server has disconnected*/
|
|
static constexpr int CONNECTION_NONESERVER = 1;
|
|
/** The connection is lost<br>Either because of a network crash or because the server no longer responds.*/
|
|
static constexpr int CONNECTION_LOST = 2;
|
|
/** Connection to the serv er is established.*/
|
|
static constexpr int CONNECTION_OK = 3;
|
|
/** A connection to the server is tried.*/
|
|
static constexpr int CONNECTION_TRYCONNECTION = 4;
|
|
|
|
//------ PlayerType ------
|
|
public:
|
|
/** continous main player, time value can be used like a timecode.<br>The time value is the position in server's project.<br>A server should use only one main player.*/
|
|
static constexpr char PLAYERTYPE_MAIN = 0x02;
|
|
/** continous player. This player plays SPIT objects sometime during the project.*/
|
|
static constexpr char PLAYERTYPE_CONTINOUS = 0x01;
|
|
/** diescrete player. This player is used to transmit single discrete values.*/
|
|
static constexpr char PLAYERTYPE_DISCRETE = 0x00;
|
|
|
|
//------ Value Flag ------
|
|
//------ used by sendRemoteObject
|
|
public:
|
|
/**Set the given value directly*/
|
|
static constexpr char VALUEFLAG_DIRECT = 0x00;
|
|
/**Increase the existing value by the given value.<br>This is usefull e.g. when instead of a fader a endless wheel is used*/
|
|
static constexpr char VALUEFLAG_INCREASE = 0x01;
|
|
/**Decrease the existing value by the given value.<br>This is usefull e.g. when instead of a fader a endless wheel is used*/
|
|
static constexpr char VALUEFLAG_DECREASE = 0x02;
|
|
|
|
//----- SPIT_Client -----
|
|
public:
|
|
SPIT_Client(string name, string projName, Callbacks calls);
|
|
virtual ~SPIT_Client();
|
|
static int s_MAX_OVERTAKING_SPIT_MESSAGES;
|
|
|
|
private:
|
|
Callbacks mCallbacks;
|
|
|
|
fos::TaskT<SPIT_Client &> *m_ThreadReceive{};
|
|
bool m_StopReceiveSPITMessages;
|
|
|
|
int m_ConnectionStatus;
|
|
bool m_DisconnectedByServer{}; // flag true = when server disconnects
|
|
string m_ID;
|
|
string m_Name;
|
|
string m_ProjName;
|
|
string m_ComputerName;
|
|
|
|
string m_ClientProjectName;
|
|
|
|
unsigned char m_MessageNumber_Send;
|
|
int m_MessageNumber_Received;
|
|
vector<SPIT_Message *> m_OvertakingSPIT_Messages;
|
|
|
|
// Server's info filled by parseConnectAnswer
|
|
string m_ServerID{};
|
|
string m_ServerName{};
|
|
string m_ServerComputerName{};
|
|
int m_ServerStepTime{-1};
|
|
|
|
//--- Server Project ---
|
|
string m_ServerProjectID;
|
|
string m_ServerProjectName;
|
|
int m_ServerFramesPerSecond;
|
|
|
|
public:
|
|
/** The ID of the client.<br>Every client instance should set an unique id*/
|
|
string getID() { return m_ID; }
|
|
/** The name of the client, should be set by the user app*/
|
|
string getName() { return m_Name; }
|
|
//----- Computer Params -----
|
|
/** The name of the client's host computer*/
|
|
string getComputerName() { return m_ComputerName; }
|
|
void setClientProjectName(string p_ClientProjectName) { m_ClientProjectName = p_ClientProjectName; }
|
|
string getClientProjectName() { return m_ClientProjectName; }
|
|
|
|
// connected Server Infos
|
|
/** The ID of the connected SPITServer*/
|
|
string getServerID() { return m_ServerID; }
|
|
/** The host computername of the connected SPITServer*/
|
|
string getServerComputerName() { return m_ServerComputerName; }
|
|
/** The name of the connected SPITServer*/
|
|
string getServerName() { return m_ServerName; }
|
|
|
|
/** Expected Refreah Rate of the connectd SPITServer.<br>
|
|
* When the server plays objects, it will do so at discrete time steps.<br>
|
|
* Play events will take place in these time steps..
|
|
*/
|
|
int getServerStepTime() { return m_ServerStepTime; }
|
|
|
|
/** Should be called when the client wants to close his project*/
|
|
void clientProjectClose();
|
|
/**
|
|
* Should be called whenever the client has a project loaded
|
|
*/
|
|
void clientProjectLoaded();
|
|
|
|
/**
|
|
*
|
|
* @param p_SPITTypeID
|
|
* @param p_ActionAssigned
|
|
*/
|
|
void setActionSPITType(string p_SPITTypeID, bool p_ActionAssigned);
|
|
void setActionSPITObject(string p_SPITObjectID, bool p_ActionAssigned);
|
|
|
|
//--------------- SPITMessage ---------------
|
|
private:
|
|
bool startReceiveSPITMessages();
|
|
void stopReceiveSPITMessages();
|
|
static void receiveSPITMessage(SPIT_Client &rM);
|
|
// Reconnect to the server when connection is lost see eventConnectionStatus and eventServerDetected
|
|
bool _doReconnect{}; // true = on eventServerDetected connect to the server identified by m_ServerID
|
|
public:
|
|
void fillHeader(SPIT_Message::Header *p_Header);
|
|
int sendSPITMessage(unique_ptr<SPIT_Message::OPPart> spitMessageOPPart);
|
|
|
|
//--------------- ServerAutoDetection SAD ---------------
|
|
public:
|
|
/** Starts the autodetection of SPITServers in the local network. If a connection is tried, the autodetection should be stopped before.*/
|
|
void startServerAutoDetect();
|
|
/** Stops the autodetection of SPITServers in the local network*/
|
|
void stopServerAutoDetect();
|
|
/** Called every time a new SPITServer is detetced in the local network */
|
|
void eventServerDetected(SAD_DetectedServer &server);
|
|
/** Called every time a prior detected SPITServer is is no longer found.*/
|
|
void eventServerLost(SAD_DetectedServer &server);
|
|
void eventServerChanged(SAD_DetectedServer &server);
|
|
|
|
//--------------- Connection ---------------
|
|
public:
|
|
/**
|
|
* Tries a connection to the SPITServer
|
|
* @param p_ServerIP ip address of the SPITServer
|
|
* @param p_ServerPort port of the SPITServer
|
|
* @param p_ClientIP IP of the client
|
|
* @param p_ClientPort if "0" any free port will be used
|
|
* @param p_LoginName maybe some SPITServer need a login - liveSHOWsoftware will not.
|
|
* @param p_LoginPassword maybe some SPITServer need a login - liveSHOWsoftware will not
|
|
* @return true = the connection try is ok, SPITServer will answer with COnnectAnswer and an eventConnectionStatus will occur.<br>
|
|
* false = something is going wrong. (client could not bind)
|
|
*/
|
|
bool connect(string p_ServerIP, string p_ServerPort, string p_ClientIP, string p_ClientPort, string p_LoginName = "", string p_LoginPassword = "");
|
|
/**
|
|
* Terminates the connection to the SPITServer.
|
|
*/
|
|
void disconnect();
|
|
|
|
private:
|
|
void disconnectInternal(int p_Cause);
|
|
void resetMessageNumberReceived();
|
|
void parseSPIT_Message(unique_ptr<SPIT_Message> p_SPITMessage);
|
|
void checkParseSPIT_Message(unique_ptr<SPIT_Message> p_SPITMessage);
|
|
void addOvertakingSPIT_Message(SPIT_Message *p_SPIT_Message);
|
|
void parseConnectAnswer(SPIT_Message::ConnectAnswer *p_ConnectAnswer);
|
|
void parseDisconnect(SPIT_Message::Disconnect *p_Disconnect);
|
|
void parseWatchdog(SPIT_Message::Watchdog *p_Watchdog);
|
|
void parseWatchdogAnswer(SPIT_Message::WatchdogAnswer *p_WatchdogAnswer);
|
|
|
|
public:
|
|
/** Used internally*/
|
|
void sendWatchdog();
|
|
/** Used internally. When the connection to the SPITServer is lost an eventConnectionStatus will occur*/
|
|
void eventWatchdogLost();
|
|
//--------------- SPIT Project ---------------
|
|
private:
|
|
void parseReportSPITProject(SPIT_Message::ReportSPITProject *p_ReportSPITProject);
|
|
void parseCloseSPITProject(SPIT_Message::CloseSPITProject *p_CloseSPITProject);
|
|
|
|
public:
|
|
/** Returns the SPITServer's project ID - may be the same as the project's name*/
|
|
string getServerProjectID();
|
|
/** Returns the SPITServer's project name*/
|
|
string getServerProjectName();
|
|
/** Returns frame rate per second. This is the time resolution in which the server transmits time data. The unit of time data is always frames.*/
|
|
int getServerFramesPerSecond();
|
|
|
|
private:
|
|
void parseRequestProjectTransfer(SPIT_Message::RequestProjectTransfer *p_RequestProjectTransfer);
|
|
void parseStartProjectTransfer(SPIT_Message::StartProjectTransfer *p_StartProjectTransfer);
|
|
void parseEndProjectTransfer(SPIT_Message::EndProjectTransfer *p_EndProjectTransfer);
|
|
|
|
public:
|
|
static void sendProject(SPIT_Client *p_PtrSPIT_Client);
|
|
|
|
// --------------- SPIT Types ---------------
|
|
public:
|
|
/**
|
|
* Creates a fixed SPITType for application actions that are always present and project independent.<br>
|
|
* Fixed SPIT types cannot be changed or deleted by the server.<br>
|
|
* These SPITTypes will be automatically added to the SPITType-List and sended to the server.
|
|
* @param p_ID an unique of the SPITType, these are always the same per client approach. Different client approaches should use different ids.
|
|
* @param p_GroupName a name which groups the actions/SPITTypes
|
|
* @param p_Name the name of the Action/SPITType
|
|
* @param p_DefaultDelay maybe there is an default delay until the action starts, this is only used for graphical representations, 0 is allowd
|
|
* @param p_DefaultDuration maybe the action has a default duration, this is only used for graphical representations, 0 is allowd
|
|
* @return the pointer to the new SPITType.
|
|
*/
|
|
SPITType *createSPITTypeFixed(string p_ID, string p_GroupName, string p_Name, long long p_DefaultDelay, long long p_DefaultDuration);
|
|
|
|
/**
|
|
* Creates a SPITType for application actions.<br>
|
|
* These SPITTypes will be automatically added to the SPITType-List and sended to the server.
|
|
* @param p_ID an unique of the SPITType, these are always the same per client approach. Different client approaches should use different ids.
|
|
* @param p_GroupName a name which groups the actions/SPITTypes
|
|
* @param p_Name the name of the Action/SPITType
|
|
* @param p_DefaultDelay maybe there is an default delay until the action starts, this is only used for graphical representations, 0 is allowd
|
|
* @param p_DefaultDuration maybe the action has a default duration, this is only used for graphical representations, 0 is allowd
|
|
* @param p_Fixed true = the server is not allowed to change this SPITType, false = the server may change or delete this SPITType
|
|
* @param p_ProjectIndepended true = the SPITType belongs to a specific project, false = the SpitType always exists for every project
|
|
* @return the pointer to the new SPITType.
|
|
*/
|
|
SPITType *createSPITType(string p_ID, string p_GroupName, string p_Name, long long p_DefaultDelay, long long p_DefaultDuration, bool p_Fixed, bool p_ProjectIndepended);
|
|
|
|
private:
|
|
// receive SPITTypes
|
|
void parseReportSPITType(SPIT_Message::ReportSPITType *p_ReportSPITType);
|
|
void parseRemoveSPITType(SPIT_Message::RemoveSPITType *p_RemoveSPITType);
|
|
int sendSPITTypeInternal(SPITType &p_SPITType);
|
|
|
|
public:
|
|
/**
|
|
* If a client wants to change a SPITType, he should send it to the server.<br>
|
|
* If the SPITTye is a fixed one and not created by the client himself, then an eventSPITType can be sent from the server, which cancels the change.<br>
|
|
* @param p_SPITTypeID the id of the SPITType to remove.
|
|
* @return 0 = is sended, -1 = is not sended
|
|
*/
|
|
bool changeSPITType(SPITType *p_SPITType);
|
|
/**
|
|
* If a client wants to remove a SPITType, he should send it to the server.<br>
|
|
* If the SPITTye is a fixed one and not created by the client himself, then an eventSPITType can be sent from the server, which cancels the deletion.<br>
|
|
* @param p_SPITTypeID the id of the SPITType to remove.
|
|
* @return 0 = is sended, -1 = is not sended
|
|
*/
|
|
int removeSPITType(string p_SPITTypeID);
|
|
|
|
public:
|
|
//--------------- SPIT Objects ---------------
|
|
private:
|
|
void parseReportSPITObject(SPIT_Message::ReportSPITObject *p_ReportSPITObject);
|
|
void parseRemoveSPITObject(SPIT_Message::RemoveSPITObject *p_RemoveSPITObject);
|
|
int sendSPITObjectInternal(SPITObject *ptrSPITObject);
|
|
|
|
public:
|
|
/**
|
|
* When the client changes a SPITObject (normally the client should not do this), then it should send the changes to the SPITServer.<br>
|
|
* The SPITServer may discard the changes and an eventSPITObject occurs.<br>
|
|
* @param p_SPITObject the pointer to the changed SPITObject.
|
|
* @return 0 = sended, -1 = not sended
|
|
*/
|
|
bool changeSPITObject(SPITObject *p_SPITObject);
|
|
/**
|
|
* When the client removes a SPITObject (normally the client should not do this), then he should send it to the SPITServer.<br>
|
|
* The SPITServer may discard the deletion and an eventSPITObject occurs.<br>
|
|
* @param p_SPITObjectID the id of the SPITObject to remove.
|
|
* @return 0 = sended, -1 = not sended
|
|
*/
|
|
int removeSPITObject(string p_SPITObjectID);
|
|
|
|
public:
|
|
//--------------- Play SPIT Objects ---------------
|
|
private:
|
|
void parsePlaySPITStart(SPIT_Message::PlaySPITStart *p_PlaySPITStart);
|
|
void parsePlaySPITObject(SPIT_Message::PlaySPITObject *p_PlaySPITObject);
|
|
void parsePlaySPITEnd(SPIT_Message::PlaySPITEnd *p_PlaySPITEnd);
|
|
void parseReportPlayStatus(SPIT_Message::ReportPlayStatus *p_ReportPlayStatus);
|
|
|
|
public:
|
|
//--------- Remote ----------
|
|
void sendRemoteObject(string p_SPITObjectID, int p_Valueppm = 0, char p_ValueFlag = 0x00);
|
|
|
|
private:
|
|
static void processSocketTask(SPIT_Client &instance);
|
|
fos::TaskT<SPIT_Client &> *sThread{};
|
|
bool abortSearch{};
|
|
bool sAnswered{};
|
|
static fos::Semaphore sStartSad;
|
|
SPITSocket *mSPITSocket;
|
|
void answerWatchdog() {
|
|
sAnswered = true;
|
|
}
|
|
};
|
|
|
|
#endif /* SPIT_CLIENT_H */
|