/* * 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 "SPITSocket.h" #include "SAD_DetectedServer.hpp" #include "SPIT_Message.h" #include "SPITType.h" #include "SPITObject.h" #include "SPITPlayer.h" #include #include using namespace std; class SPIT_Client : I_SAD_Client { public: /** Maximal length of a SPITMessage*/ static const int MAXSPITMESSAGEBYTECOUNT = 512; enum ServerEvent { Detect, Lost, Changed, }; 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(*onStartProjectTransfer)(); void(*onEndProjectTransfer)(); void(*onProjectClosed)(string); void(*onProjectReport)(string p_ProjectID, string p_ProjectName, int p_FramesPerSeoond); void(*onSpitType)(bool p_New, const SPITType &p_SPITType); void(*onSpitTypeRemote)(bool p_New, const SPITType &p_SPITType); void(*onSpitObject)(bool p_New, const SPITType &p_SPITType, const SPITObject &p_SPITObject); void(*onSpitObjectRemote)(bool p_New, const SPITType &p_SPITType, const SPITObject &p_SPITObject); void(*onSpitTypeRemoved)(const SPITType &p_SPITType); void(*onSpitTypeRemoteRemoved)(const SPITType &p_SPITType); void(*onSpitObjectRemoved)(const SPITType &p_SPITType, const SPITObject &p_SPITObject); void(*onSpitObjectRemoteRemoved)(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.
Either no connect tried or disconnected*/ static const int CONNECTION_NONE = 0; /** Server has disconnected*/ static const int CONNECTION_NONESERVER = 1; /** The connection is lost
Either because of a network crash or because the server no longer responds.*/ static const int CONNECTION_LOST = 2; /** Connection to the serv er is established.*/ static const int CONNECTION_OK = 3; /** A connection to the server is tried.*/ static const int CONNECTION_TRYCONNECTION = 4; //------ PlayerType ------ public: /** continous main player, time value can be used like a timecode.
The time value is the position in server's project.
A server should use only one main player.*/ static const char PLAYERTYPE_MAIN = 0x02; /** continous player. This player plays SPIT objects sometime during the project.*/ static const char PLAYERTYPE_CONTINOUS = 0x01; /** diescrete player. This player is used to transmit single discrete values.*/ static const char PLAYERTYPE_DISCRETE = 0x00; //------ Value Flag ------ //------ used by sendRemoteObject public: /**Set the given value directly*/ static const char VALUEFLAG_DIRECT = 0x00; /**Increase the existing value by the given value.
This is usefull e.g. when instead of a fader a endless wheel is used*/ static const char VALUEFLAG_INCREASE = 0x01; /**Decrease the existing value by the given value.
This is usefull e.g. when instead of a fader a endless wheel is used*/ static const 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 * 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 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.
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.
* When the server plays objects, it will do so at discrete time steps.
* 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(SPIT_Message::OPPart& p_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(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4); /** Called every time a prior detected SPITServer is is no longer found.*/ void eventServerLost(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4); void eventServerChanged(string p_ID, string p_Name, string p_ComputerName, string p_IP, string p_Port, string p_Addition, string p_ProjectName, string p_ClientIP, bool p_IsIP4); //--------------- 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.
* 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 p_SPITMessage); void checkParseSPIT_Message(unique_ptr 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.
* Fixed SPIT types cannot be changed or deleted by the server.
* 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.
* 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.
* 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.
* @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.
* 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.
* @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.
* The SPITServer may discard the changes and an eventSPITObject occurs.
* @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.
* The SPITServer may discard the deletion and an eventSPITObject occurs.
* @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* sThread{}; bool abortSearch{}; bool sAnswered{}; static fos::Semaphore sStartSad; SPITSocket * mSPITSocket; void answerWatchdog() { sAnswered = true; } }; #endif /* SPIT_CLIENT_H */