744 lines
33 KiB
C++
744 lines
33 KiB
C++
|
|
#include "MyApp.h"
|
|
#include "Task.hpp"
|
|
#include "esp_log.h"
|
|
#include "SPIT_Handler.h"
|
|
|
|
string MyApp::s_ClientName = "MySPITApp_Client"; //Name of this Client
|
|
const char * TAG = "SPIT";
|
|
|
|
|
|
void SpitClientApp() {
|
|
ESP_LOGI(TAG, "Starting SPIT task");
|
|
// fos::Task spit(SPIT_Handler::run,"SpitHandl");
|
|
|
|
auto ptrMyApp = std::make_unique<MyApp>();
|
|
|
|
//load a client project
|
|
//the client project may belong to a server's project or may be independend of server's projects
|
|
//if the client project belongs to a specific server project
|
|
// -> add some code in the function eventProjectReport(..) (for excample create special SPITTypes or Actions
|
|
//if the client project is independend od server's project
|
|
// -> use loadClientProject() to create all SPITypes and actions
|
|
//An action is bound to a SPITType and called when the server plays a SPITObject that references the SPITType
|
|
// see eventPlayObject
|
|
ptrMyApp->loadClientProject();
|
|
|
|
//start autodetection of SPITServers
|
|
//autodetection of SPITServers ends automaticallay when this SPITClient is connected to a SPITServer
|
|
ptrMyApp->startServerAutoDetect();
|
|
|
|
while (true) {
|
|
fos::Task::delayMs(10000);
|
|
ptrMyApp->testLiveShowRemote(); //This is an excample how to remote control the liveSHOWsoftware
|
|
}
|
|
}
|
|
|
|
MyApp::MyApp() {
|
|
m_SPIT_Client = new SPIT_Client(this);
|
|
//You need to give your application a descriptive name
|
|
m_SPIT_Client->setName(s_ClientName);
|
|
|
|
//The following members are set in loadClientProject function.
|
|
m_ClientProjectID = "";
|
|
|
|
//The following members are set in the eventConnectionStatus
|
|
m_ServerID = "";
|
|
m_ServerComputerName = "";
|
|
m_ServerName = "";
|
|
m_ServerStepTime = -1;
|
|
|
|
//The follwing members are set in eventProjectReport
|
|
m_ServerProjectID = "";
|
|
m_ServerProjectName = "";
|
|
m_ServerFramesPerSecond = 44100; //is reset in eventProjectReport.
|
|
|
|
//Used to decide if a reconnection is tried after the connection is lost
|
|
m_FlagReconnect = false;
|
|
}
|
|
|
|
MyApp::~MyApp() {
|
|
//To close the connection and all other stuff delete the SPIT_Client instance
|
|
if (m_SPIT_Client != NULL) {
|
|
delete m_SPIT_Client;
|
|
}
|
|
}
|
|
|
|
//Following functions fullfill the SPIT_ClientInterface
|
|
//They are needed when the server sends his project, see eventProjectReport
|
|
string MyApp::getClientProjectID() {
|
|
return m_ClientProjectID;
|
|
}
|
|
|
|
//Following functions fullfill the SPIT_ClientInterface
|
|
//They are needed when the server sends his project, see eventProjectReport
|
|
string MyApp::getClientProjectName() {
|
|
return m_ClientProjectName;
|
|
}
|
|
|
|
void MyApp::loadClientProject() {
|
|
//----- close current client project -----
|
|
if (m_SPIT_Client != NULL) {
|
|
m_SPIT_Client->clientProjectClose();
|
|
}
|
|
|
|
if (m_SPIT_Client != NULL) {
|
|
//Create SPITTypes for all discrete and unchangable functions of this client. Fixed means the server can't change or remove the SPITType.
|
|
SPITType* ptrSPITType1Fix;
|
|
ptrSPITType1Fix = m_SPIT_Client->createSPITTypeFixed("MySPITAPP_Action1ID", "ActionGroupName", "Action1Name", 0, 0);
|
|
|
|
SPITType* ptrSPITType2Fix;
|
|
ptrSPITType2Fix = m_SPIT_Client->createSPITTypeFixed("MySPITAPP_Action2ID", "ActionGroupName", "Action2Name", 0, 0);
|
|
|
|
//When an action exist which should be done whenever a SPITObject with this SPITType is played, <br>
|
|
//then you should 'setAssignedActionType' to true
|
|
m_SPIT_Client->setActionSPITType(ptrSPITType1Fix->getID(), true);
|
|
m_SPIT_Client->setActionSPITType(ptrSPITType2Fix->getID(), true);
|
|
//later in the eventPlayObject you can react with your action code for "Action1" and "Action2"
|
|
}
|
|
|
|
if (m_SPIT_Client != NULL) {
|
|
m_SPIT_Client->clientProjectLoaded();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
//---------- ServerAutoDetection ----------
|
|
|
|
void MyApp::startServerAutoDetect() {
|
|
if (m_SPIT_Client != NULL) {
|
|
m_SPIT_Client->startServerAutoDetect();
|
|
}
|
|
}
|
|
void MyApp::stopServerAutoDetect() {
|
|
if (m_SPIT_Client != NULL) {
|
|
m_SPIT_Client->stopServerAutoDetect();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
//----- All events are delegated to the SPIT_Handler.
|
|
//----- The follwoing event functions are called
|
|
//----- by the one thread s_HandlerThread of the SPIT_Handler
|
|
//------------------------------------------------------
|
|
|
|
/**
|
|
* Is always called when a new SPIT server is found.<br>
|
|
* For this you have to call SPIT_Client::startServerAutoDetect.<br>
|
|
* @param p_DetectedServer a reference to a copy of a SAD_DetectedServer instance.<br>
|
|
* After this function call the copy of the SAD_DetectedServer will be deleted!!<br>
|
|
*/
|
|
void MyApp::eventServerDetected(const SAD_DetectedServer& p_DetectedServer) {
|
|
//fetch the infoemations from the p_DetectedServer
|
|
ESP_LOGD(TAG, "SERVER DETECTED");
|
|
ESP_LOGD(TAG, " Name: %s", p_DetectedServer.getName().data());
|
|
ESP_LOGD(TAG, " ID: %s", p_DetectedServer.getID().data());
|
|
ESP_LOGD(TAG, " Computer: %s", p_DetectedServer.getComputerName().data());
|
|
ESP_LOGD(TAG, " IP: %s", p_DetectedServer.getIP().data());
|
|
ESP_LOGD(TAG, " Port: %s", p_DetectedServer.getPort().data());
|
|
ESP_LOGD(TAG, " Addition: %s", p_DetectedServer.getAdditions().data());
|
|
ESP_LOGD(TAG, " ClientIP: %s", p_DetectedServer.getClientIP().data());
|
|
|
|
bool boolSuccess = false;
|
|
//---------- RECONNECTION ----------
|
|
//If a connection has been established and the connection is lost -> reconnect
|
|
if (m_FlagReconnect == true) {
|
|
//check if the server is the same as prior connected
|
|
if (m_ServerID == p_DetectedServer.getID()) {
|
|
if (m_SPIT_Client != NULL) {
|
|
stopServerAutoDetect();
|
|
ESP_LOGI(TAG,"reconnect to %s", p_DetectedServer.getIP().data());
|
|
boolSuccess = m_SPIT_Client->connect(p_DetectedServer.getIP(), p_DetectedServer.getPort(), p_DetectedServer.getClientIP(), "0"); //ClientPort = "0" meeans use any port
|
|
if (boolSuccess == true) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Excample use the first detected LOOPBACK server, means the server runs on the same computer as this client
|
|
if (p_DetectedServer.getIpIsLoopback() == true) { //omit the if condition if you want to use the first server found
|
|
return;
|
|
}
|
|
boolSuccess = false;
|
|
//Stop auto detection because a suitable server was found
|
|
stopServerAutoDetect();
|
|
if (m_SPIT_Client != NULL) {
|
|
ESP_LOGI(TAG,"connect to %s", p_DetectedServer.getIP().data());
|
|
boolSuccess = m_SPIT_Client->connect(p_DetectedServer.getIP(), p_DetectedServer.getPort(), p_DetectedServer.getClientIP(), "0"); //ClientPort = "0" meeans use any port
|
|
}
|
|
if (boolSuccess == false) {
|
|
//connection message could not be sent -> better to restart AutoDetection
|
|
startServerAutoDetect();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Is always called when a SPIT server does not respond anymore.<br>
|
|
* For this you have to call SPIT_Client::startServerAutoDetect.<br>
|
|
* This is an information used by autodetection and not by an established connection.<br>
|
|
* <br>
|
|
* When a connection to a SPITServer is established, the autodetection should be stopped.<br>
|
|
* The connection lost event is detected by eventConnectionStatus<br>
|
|
* <br>
|
|
* @param p_DetectedServer a reference to a copy of a SAD_DetectedServer instance.<br>
|
|
* After this function call the copy of the SAD_DetectedServer will be deleted!!<br>
|
|
*/
|
|
void MyApp::eventServerLost(const SAD_DetectedServer& p_DetectedServer) {
|
|
ESP_LOGW(TAG, "Server lost Name: %s IP: %s", p_DetectedServer.getName().data(), p_DetectedServer.getIP().data());
|
|
}
|
|
|
|
|
|
//---------------------------------------
|
|
//---------- Connecting event ----------
|
|
|
|
void MyApp::eventConnectionStatus(string p_ServerID, string p_ServerComputerName, string p_ServerName, int p_ServerStepTime, int p_ConnectionStatus, int p_OldConnectionStatus) {
|
|
ESP_LOGD(TAG, "eventConnectionStatus %d ", p_ConnectionStatus);
|
|
switch(p_ConnectionStatus) {
|
|
case SPIT_Client::CONNECTION_NONE:
|
|
ESP_LOGD(TAG, "not connected");
|
|
break;
|
|
case SPIT_Client::CONNECTION_NONESERVER:
|
|
ESP_LOGD(TAG, "connection terminated by server");
|
|
//call eventProjectClosed because this may not be sended by the server,
|
|
//when the connstion is closed
|
|
eventProjectClosed(m_ServerProjectID);
|
|
|
|
//Server has terminated the connection -> start a new game
|
|
m_FlagReconnect = false;
|
|
startServerAutoDetect();
|
|
break;
|
|
case SPIT_Client::CONNECTION_OK:
|
|
ESP_LOGD(TAG, "connection established");
|
|
stopServerAutoDetect(); //normally you should stop the autodetection before you try a connection
|
|
//This is redundand
|
|
m_ServerID = p_ServerID;
|
|
m_ServerComputerName = p_ServerComputerName;
|
|
m_ServerName = p_ServerName;
|
|
m_ServerStepTime = p_ServerStepTime;
|
|
|
|
//Maybe you want to reconnect, see eventServerDetected(...)
|
|
//Here the connection is established -> don't reconnect at eventServerDetected(...)
|
|
m_FlagReconnect = false;
|
|
break;
|
|
case SPIT_Client::CONNECTION_LOST:
|
|
ESP_LOGD(TAG, "connection lost");
|
|
//Maybe you want to reconnect, see eventServerDetected(...)
|
|
//We have lost the connection -> set the flag to true and start the autodetection to reconnect at eventServerDetected(...)
|
|
m_FlagReconnect = true;
|
|
startServerAutoDetect();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
//---------- Server's Project events ------------------------
|
|
/**
|
|
* The Server reports his loaded project
|
|
* Called when<br>
|
|
* a) the connection to the server is established.<br>
|
|
* b) server load a new project<br>
|
|
* c) server saves the project under a new name<br>
|
|
* @param p_ProjectID the server project's id<br>
|
|
* (maybe the filename of the project or a part o it or the same as p_ProjectName)
|
|
* @param p_ProjectName the server project's name
|
|
* @param p_FramesPerSeoond All times in SPIT are given in frames. FramesPerSecond can be used to convert frames to seconds....
|
|
*/
|
|
void MyApp::eventProjectReport(string p_ProjectID, string p_ProjectName, int p_FramesPerSeoond) {
|
|
ESP_LOGD(TAG, "eventProjectReport ID: %s Name: %s FramesPerSecond: %d", p_ProjectID.data(), p_ProjectName.data(), p_FramesPerSeoond);
|
|
m_ServerProjectID = p_ProjectID;
|
|
m_ServerProjectName = p_ProjectName;
|
|
m_ServerFramesPerSecond = p_FramesPerSeoond;
|
|
|
|
//set the frames per second as the server - perhaps the client's time values have to be recalculated.
|
|
m_ServerFramesPerSecond = p_FramesPerSeoond;
|
|
|
|
//When the this client's project depends on the server's project -> load some specific informations here
|
|
}
|
|
|
|
/**
|
|
* Called when the server closes his project.<br>
|
|
* @param p_ProjectID the id of the project<br>
|
|
* The server loads only one project at time-> the ID is not actually necessary
|
|
*/
|
|
void MyApp::eventProjectClosed(string p_ProjectID) {
|
|
ESP_LOGD(TAG, "eventProjectClosed ID: %s", p_ProjectID.data());
|
|
//If we don't save SPITServer's project specific information
|
|
//perhaps close all SPITObjects and RemoteSPITObjects to avoid conflicts, when the SPITServer loads a new project
|
|
//SPITObject::clearSPITObjects();
|
|
//SPITObject::clearSPITObjectsRemote();
|
|
}
|
|
|
|
/**
|
|
* The server starts the transfer of its project, that means:.<br>
|
|
* All SPITTypes and SPITObjects available on the server are transferred in the following.<br>
|
|
* Several calls of eventSPITType and eventSPITObject will occur.<br>
|
|
* At the end eventEndProjectTransfer is called.
|
|
*/
|
|
void MyApp::eventStartProjectTransfer() {
|
|
ESP_LOGD(TAG, "eventStartProjectTransfer");
|
|
}
|
|
/**
|
|
* The transfer of the server's SPITTypes and SPITObjects is finished.<br>
|
|
* AFter this all eventSPITType and eventSPITObject means that new types , objects are created or changed.
|
|
*/
|
|
void MyApp::eventEndProjectTransfer() {
|
|
ESP_LOGD(TAG, "eventEndProjectTransfer");
|
|
}
|
|
|
|
|
|
//----------------------------------------------------
|
|
//--------- SPITType events ----------
|
|
|
|
// SPITTypes describing an action or a type of an action.
|
|
// To trigger an action SPITObjects are used. Every SPITObject has one of the SPITTypes assigned.<br>
|
|
// There are two ways action can be triggered, either the server triggers an action on the client,
|
|
// or the client sends remote control commands to the server.
|
|
// a) normal types that are comitted to the client and played per SPITObjects by server, so the client can react with actions.
|
|
// b) Remote types are used for remote control of the server and are played by the client via SPIT objects.
|
|
//All normal SPITTypes are listet in a static unordered_map in the SPITType class.
|
|
//All remote SPITTypes are listet in a seperate static unordered_map in the SPITType class.
|
|
//You can use the SPITType::get... functions to deal with them.
|
|
//The SPITType class has a static recursive_mutex, you get a pointer of the mutex by: SPITType::getMutex();
|
|
//To be thread save you should cover your code with a lock sequence:
|
|
/*
|
|
{ //start of the lock sequence
|
|
unique_lock<recursive_mutex> o_LockType(*SPITType::getMutex());
|
|
//got the lock
|
|
|
|
//fetch SPITType and deal with, but don't waste time while you holding the lock
|
|
//Excample
|
|
SPITType* ptrSPITType;
|
|
for (int i = 0; i < SPITType::getSPITTypeCount(); i ++) {
|
|
ptrSPITType = SPITType::getSPITType(i);
|
|
if (ptrSPITType == NULL) break;
|
|
//Do something with ptrSPITType
|
|
//bew aware after you leave the lock sequence the ptrSPITType is no longer save!!
|
|
}
|
|
} //end of the lock sequence
|
|
|
|
//For Remote Types you can use the getSPITTypeRemote... functions
|
|
*/
|
|
|
|
/**
|
|
* Called when the server has created, loaded or changed a SPITType.<br>
|
|
* May also occur when the server confirms a SPITType created or changed by the client.<br>
|
|
* @param p_New true = server created a new SPITType<br>
|
|
* false = server changed a existing SPITType<br>
|
|
* @param p_SPITType a reference to a copy of the SPITType instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
*/
|
|
void MyApp::eventSPITType(bool p_New, const SPITType& p_SPITType) {
|
|
//fetch information of the SPITType
|
|
if (p_New) {
|
|
//a new SPITType is created
|
|
ESP_LOGD(TAG, "eventSPITType NEW");
|
|
}
|
|
else {
|
|
//an existing SPITType is changed
|
|
ESP_LOGD(TAG, "eventSPITType CHANGED");
|
|
}
|
|
ESP_LOGD(TAG, " ID: %s GroupName: %s Name: %s confirmed: %d", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed());
|
|
|
|
//Check your actions
|
|
//Whenever you provide an action for this SPITType take this over in your code.
|
|
//call m_SPIT_Client->setActionSPITType(p_SPITType.getID(), true);
|
|
|
|
//for our little excample as described in loadClientProject we do following
|
|
if (m_SPIT_Client != NULL) {
|
|
//This may be redundand, because we defined the SPITTypes as fixed, so the server can't change them
|
|
//But foe all SPITTypes which are not fixed we need to setActionSPITType
|
|
if ("MySPITAPP_Action1ID" == p_SPITType.getID()) {
|
|
m_SPIT_Client->setActionSPITType(p_SPITType.getID(), true);
|
|
}
|
|
if ("MySPITAPP_Action2ID" == p_SPITType.getID()) {
|
|
m_SPIT_Client->setActionSPITType(p_SPITType.getID(), true);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Called when the server has created or changed a Remote SPITType.<br>
|
|
* Remote SPITType are used in Remote SPITObjects. A Remote SPITObject is used to remote control the SPITServer.
|
|
* @param p_New true = server created a new SPITType<br>
|
|
* false = server changed a existing SPITType<br>
|
|
* @param p_SPITType a reference to a copy of the SPITType instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
*/
|
|
void MyApp::eventSPITTypeRemote(bool p_New, const SPITType& p_SPITType) {
|
|
if (p_New) {
|
|
ESP_LOGD(TAG, "eventSPITTypeRemote NEW");
|
|
}
|
|
else {
|
|
//we had to inform all Remote SPITObjects using the p_SPITType
|
|
//perhaps the SPITObject uses information from the SPITType
|
|
SPITObject* ptrSPITObject;
|
|
int intSPITObjectCount;
|
|
intSPITObjectCount = SPITObject::getSPITObjectRemoteCount();
|
|
for (int intObject = 0; intObject < intSPITObjectCount; intObject++) {
|
|
ptrSPITObject = SPITObject::getSPITObjectRemote(intObject);
|
|
if (ptrSPITObject == NULL) continue;
|
|
if (ptrSPITObject->getSPITTypeID() == p_SPITType.getID()) {
|
|
//call ecentSPITObjectRemote
|
|
eventSPITObjectRemote(false, p_SPITType, *ptrSPITObject);
|
|
}
|
|
}
|
|
ESP_LOGD(TAG, "eventSPITTypeRemote CHANGED");
|
|
}
|
|
ESP_LOGD(TAG, "ID: %s GroupName: %s Name: %s confirmed: %d",
|
|
p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data(), p_SPITType.getConfirmed());
|
|
//this is a remote SPITType, if you want you can list this for later remote use.
|
|
}
|
|
|
|
/**
|
|
* Called when the server has removed a SPITType.<br>
|
|
* After this function has been exited the SPITType is emeoved from the SPITType-List and the pointer is deleted.<br>
|
|
* So use the pointer immediately or use the copyconstructor to make a copy for extended use.
|
|
* You have to release the copy yourself later (delete ptr...)
|
|
* @param p_SPITType a reference to a copy of the SPITType instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
*/
|
|
void MyApp::eventSPITTypeRemoved(const SPITType& p_SPITType) {
|
|
ESP_LOGD(TAG, "eventSPITType Removed");
|
|
ESP_LOGD(TAG, " ID: %s GroupName: %s Name: %s\n", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data());
|
|
|
|
//Check your actions
|
|
//take the removal of the SPITType over in your code
|
|
|
|
//CAUTION: Deleted SPIT types can be added later again (perhaps per UNDO on the SPITServer)
|
|
//-> don't remove your assigned action immediately - keep it to reassign it later
|
|
}
|
|
/**
|
|
* Called when the server has removed a Remote SPITType.<br>
|
|
* Remote SPITType are used in Remote SPITObjects. A Remote SPITObject is used to remote control the SPITServer.
|
|
* After this function has been exited the SPITType is emeoved from the Remote SPITType-List and the pointer is deleted.<br>
|
|
* So use the pointer immediately or use the copyconstructor to make a copy for extended use.
|
|
* You have to release the copy yourself later (delete ptr...)
|
|
* @param p_SPITType a reference to a copy of the SPITType instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
*/
|
|
void MyApp::eventSPITTypeRemoteRemoved(const SPITType& p_SPITType) {
|
|
ESP_LOGD(TAG, "eventSPITTypeRemote Removed");
|
|
ESP_LOGD(TAG, " ID: %s GroupName: %s Name: %s\n", p_SPITType.getID().data(), p_SPITType.getGroupName().data(), p_SPITType.getName().data());
|
|
|
|
//This is a remote SPITType
|
|
//If you have listet this prior you should remove it from the list
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------
|
|
//--------- SPITObject events ----------
|
|
// Every SPITObjects has one one SPITType assigned.
|
|
// Whenever an action is to be triggered, play events are sent with the corresponding SPITObject.
|
|
// All SPITObjects are listet in a static unordered_map in the SPITObject class.
|
|
// All Remote SPITObjects are listet in a seperate unordered_map in the SPITObject class;
|
|
// You can use the SPITObject::get... functions to deal with them.
|
|
// The SPITObject class has a static recursive_mutex, you get a pointer of the mutex by: SPITObject::getMutex();
|
|
// To be thread save you should cover your code with a lock sequence:
|
|
/*
|
|
{ //start of the lock sequence
|
|
unique_lock<recursive_mutex> o_LockObject(*SPITObject::getMutex());
|
|
//got the lock
|
|
|
|
//fetch SPITObjects and deal with, but don't waste time while you holding the lock
|
|
//Excample
|
|
SPITObject* ptrSPITObject;
|
|
for (int i = 0; i < SPITObject::getSPITObjectCount(); i++) {
|
|
ptrSPITObject = SPITObject::getSPITObject(i);
|
|
if (ptrSPITObject == NULL) break;
|
|
//Do something with ptrSPITObject
|
|
//bew aware after you leave the lock sequence the ptrSPITObject is no longer save!!
|
|
}
|
|
} //end of the lock sequence
|
|
|
|
//For Remote Objects you can use the getSPITObjectRemote... functions
|
|
*/
|
|
|
|
|
|
/**
|
|
* Called when the server has created, loaded or changed a SPITObject.<br>
|
|
* May also occur when the server confirms a SPITObject created by the client, what the client should never do!!.<br>
|
|
* @param p_New true = server created a new SPITObject<br>
|
|
* false = server changed a existing SPITObject<br>
|
|
* @param p_SPITType a reference to a copy of the associated SPITType instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
* @param p_SPITObject a reference to a copy of the SPITObject instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
*/
|
|
void MyApp::eventSPITObject(bool p_New, const SPITType& p_SPITType, const SPITObject& p_SPITObject) {
|
|
if (p_New) {
|
|
ESP_LOGD(TAG, "eventSPITObject NEW");
|
|
}
|
|
else {
|
|
ESP_LOGD(TAG, "eventSPITObject CHANGED");
|
|
}
|
|
ESP_LOGD(TAG, " ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data());
|
|
|
|
//check your actions
|
|
//Whenever you provide an action for this SPITObject take this over in your code.
|
|
//call m_SPIT_Client->setActionSPITObject(p_SPITObject.getID(), true);
|
|
|
|
//for our little excample as described in loadClientProject:
|
|
//We have only actions for SPITTypes - means every SPITObject with the associated "Actionx"-SPITTypes will trigger the action when it is played
|
|
//-> no need to do something here, because setActionSPITType has been set prior and the SPITObject will automatically inherits this
|
|
//SPITObjects with other SPITTypes asscciated will trigger no actions
|
|
|
|
}
|
|
/**
|
|
* Called when the server has created or changed a Remote SPITObject.<br>
|
|
* A Remote SPITObject is used to remote control the SPITServer.
|
|
* @param p_New true = server created a new remote SPITObject<br>
|
|
* false = server changed a existing remote SPITObject<br>
|
|
* @param p_SPITType a reference to a copy of the associated SPITType instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
* @param p_SPITObject a reference to a copy of the SPITObject instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
*/
|
|
void MyApp::eventSPITObjectRemote(bool p_New, const SPITType& p_SPITType, const SPITObject& p_SPITObject) {
|
|
if (p_New) {
|
|
ESP_LOGD(TAG, "eventSPITObjectRemote NEW");
|
|
}
|
|
else {
|
|
ESP_LOGD(TAG, "eventSPITObjectRemote CHANGED");
|
|
}
|
|
ESP_LOGD(TAG, " ID: %s Name: %s -> SPITType: %s", p_SPITObject.getID().data(), p_SPITObject.getName().data(), p_SPITType.getName().data());
|
|
|
|
//This is a remote SPITObject which can be used to remote control the server.
|
|
//If you want you can list this for later use
|
|
}
|
|
|
|
/**
|
|
* Called when the server has removed a SPITObject.<br>
|
|
* After this function has been exited the SPITObject is emeoved from the SPITObject-List and the pointer is deleted.<br>
|
|
* So use the pointer immediately or use the copyconstructor to make a copy for extended use.
|
|
* You have to release the copy yourself later (delete ptr...)
|
|
* @param p_SPITType a reference to a copy of the associated SPITType instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
* @param p_SPITObject a reference to a copy of the SPITObject instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
*/
|
|
void MyApp::eventSPITObjectRemoved(const SPITType& p_SPITType, const SPITObject& p_SPITObject) {
|
|
ESP_LOGD(TAG, "eventSPITObject Removed");
|
|
ESP_LOGD(TAG, " ID: %s Name: %s\n", p_SPITObject.getID().data(), p_SPITObject.getName().data());
|
|
|
|
//Check your actions
|
|
//take the removal of the SPITObject over in your code
|
|
|
|
//CAUTION: Deleted SPITObjects can be added later again (perhaps per UNDO on the SPITServer)
|
|
//-> don't remove your assigned action immediately - keep it to reassign it later
|
|
}
|
|
/**
|
|
* Called when the server has removed a Remote SPITObject.<br>
|
|
* A Remote SPITObject is used to remote control the SPITServer.
|
|
* After this function has been exited the SPITObject is emeoved from the SPITObject-List and the pointer is deleted.<br>
|
|
* So use the pointer immediately or use the copyconstructor to make a copy for extended use.
|
|
* You have to release the copy yourself later (delete ptr...)
|
|
* @param p_SPITType a reference to a copy of the associated SPITType instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
* @param p_SPITObject a reference to a copy of the SPITObject instance.<br>
|
|
* The reference is deleted after this function call!!
|
|
*/
|
|
void MyApp::eventSPITObjectRemoteRemoved(const SPITType& p_SPITType, const SPITObject& p_SPITObject) {
|
|
ESP_LOGD(TAG, "eventSPITObjectRemote Removed");
|
|
ESP_LOGD(TAG, " ID: %s Name: %s\n", p_SPITObject.getID().data(), p_SPITObject.getName().data());
|
|
|
|
//This is a remote SPITObject
|
|
//If you have listet this prior you should remove it from the list
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
//---------------- Playing SPITObjects ----------------
|
|
// Following is called when the SPITServer play SPITObjects.
|
|
// For every step the server does following sequence occurs:
|
|
// a) eventPlay
|
|
// b) several eventPlayObject for each actual played SPITObjectin this step
|
|
// NEXT STAP of the server
|
|
// a) eventPlay
|
|
// b) several eventPlayObject for each actual played SPITObject in this step
|
|
// ...
|
|
|
|
// SPITServer may use several methods for playing SPITObjects.
|
|
// e.g. liveSHOWsoftware has the timeline and jingles which plays objects, where the timeline the main player is.
|
|
// SPIT distinguishes between the different players. All eventPlay... functions contain the information which player plays the SPIT object.
|
|
|
|
void MyApp::eventPlay(string p_PlayerID, string p_PlayerName, char p_PlayerType, bool p_PlayerIsRunning, long long p_TimeFrames) {
|
|
ESP_LOGD(TAG, "eventPlay Player: %s Runs: %d Time: %lld", p_PlayerName.data(), p_PlayerIsRunning, p_TimeFrames);
|
|
|
|
switch(p_PlayerType) {
|
|
case SPIT_Client::PLAYERTYPE_MAIN:
|
|
//p_FrameTimes contains the position inside the server's project, we can use it like a timecode
|
|
int intMilliseconds;
|
|
intMilliseconds= (int)(((double)p_TimeFrames / (double)m_ServerFramesPerSecond) * 1000);
|
|
break;
|
|
case SPIT_Client::PLAYERTYPE_CONTINOUS:
|
|
//The olayer is playing only single Object sequences sometime during the project
|
|
break;
|
|
case SPIT_Client::PLAYERTYPE_DISCRETE:
|
|
//Only discrete values where submitted, e.g the fader position of remote faders.
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Called when the SPITServer plays a SPITObject. For every played SPITObject one eventPlayObject is called.<br>
|
|
* You can decide here which action should be done or not.<br>
|
|
*
|
|
* @param p_Started true = The SPITObject is newly played (e.g. in liveSHOWsoftware the cursor enters the SPITObject)
|
|
* @param p_Ended Das true = Playback of SPITObject finished (e.g. in liveSHOWsoftware the cursor has exited the SPIT object)
|
|
* @param p_SPITType the associated SPITType of p_SPITObject
|
|
* @param p_SPITObject the actual played or stopped SPITObject
|
|
* @param p_PlayObject contains information about the play status:<br>
|
|
* frame where the cursor is inside the SPITObject<br>
|
|
* whether the player is running or not<br>
|
|
* the actual value of the SPITObject (in liveSHOWsoftware objects ma faded in or out or the main value is decreased, ..<br>
|
|
*/
|
|
void MyApp::eventPlayObject(string p_PlayerID, bool p_Started, bool p_Ended, const SPITType& p_SPITType, const SPITObject& p_SPITObject, const SPITPlayer::PlayObject& p_PlayObject) {
|
|
// p_PlayObject.getValue() contain the value in ppm (we can calculate value between 0.0 and 1.0)
|
|
// p_SPITObject.getValueFactor() or redundand p_PlayObject.getValueFactor()
|
|
// contains the factor the above value should be multiplicated to get the end value.
|
|
double doubleValue = ((double)p_PlayObject.getValue()/1000000)*((double)p_PlayObject.getValueFactor()/1000000);
|
|
|
|
//Other factors besides value may be of interest
|
|
//p_PlayObject.getFrameInside() contains the play position inside the SPITObject
|
|
//p_SPITObject.getFrameLength() contains the length of the SPITObject
|
|
//-> we can calculate the position 0.0 to 1.0 where the Object is played
|
|
|
|
//in liveSHOWsoftware the player may play two different position in the SPITObject to mix them down, e.g. a SceneBridge is played
|
|
//We can get the second (pre played) position: p_PlayObject.getFrameInsidePrePosition();
|
|
|
|
ESP_LOGD(TAG, "eventPlayObject Player: %s is running: %d Object Started: %d Stopped: %d", p_PlayObject.getPlayerName().data(), p_PlayObject.getPlayerIsRunning(), p_Started, p_Ended);
|
|
ESP_LOGD(TAG, " SPITType: %s SPITObject: %s Position: %lld Value: %f\n", p_SPITType.getName().data(), p_SPITObject.getName().data(), p_PlayObject.getFrameInside(), doubleValue);
|
|
|
|
//check for your actions to do
|
|
|
|
//In our little excample decribed in loadClientProject:
|
|
//We want to react to SPIT types, no matter which SPIT object is currently being played.
|
|
//-> check not the SPITObject itself but the associated SPITType
|
|
bool boolPLayerIsRunning = p_PlayObject.getPlayerIsRunning();
|
|
if (p_SPITType.getID() == "MySPITAPP_Action1ID") { //do Action 1
|
|
//we can get some information about the play status
|
|
if (p_Started == true) {
|
|
ESP_LOGD(TAG, "MyApp AKTION 1 started Value: %f and running: %d", doubleValue, boolPLayerIsRunning);
|
|
}
|
|
else if (p_Ended == true) {
|
|
ESP_LOGD(TAG, "MyApp AKTION 1 ended"); //p_PlayObject.getFrameInside() is -1
|
|
}
|
|
else {
|
|
ESP_LOGD(TAG, "MyApp AKTION 1 is played Value: %f and running: %d", doubleValue, boolPLayerIsRunning);
|
|
}
|
|
}
|
|
else if (p_SPITType.getID() == "MySPITAPP_Action2ID") { //do Action 2
|
|
if (p_Started == true) {
|
|
ESP_LOGD(TAG, "AKTION 2 started Value: %f and running: %d", doubleValue, boolPLayerIsRunning);
|
|
}
|
|
else if (p_Ended == true) {
|
|
ESP_LOGD(TAG, "AKTION 2 ended"); //p_PlayObject.getFrameInside() is -1
|
|
}
|
|
else {
|
|
ESP_LOGD(TAG, "AKTION 2 is played Value: %f and running: %d", doubleValue, boolPLayerIsRunning);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
//---------------- Remote Control SPITServer ----------------
|
|
// The SPITServer has sent all possibilities to control it remotely - remote SPITObjects - see eventSPITObjectRemote
|
|
// Some of them may control functionality with values (fader psotions for loudness of sound, ...).
|
|
// When the server changes one of these value objects, it sends an eventPlayRemoteObjectStatus.
|
|
|
|
/**
|
|
* Called when a remote SpitObject which value function is changed by the server.<br>
|
|
* This allows the Client to adjust its display for the remote command.<br>
|
|
* @param p_SPITType the assigned remote SPITType of p_SPITObject
|
|
* @param p_SPITObject the remote SPITObject which is changed
|
|
* @param p_FrameInsideObject can be discarded
|
|
* @param p_Value the new value
|
|
*/
|
|
void MyApp::eventPlayRemoteObjectStatus(const SPITType& p_SPITType, const SPITObject& p_SPITObject, long long p_FrameInsideObject, int p_Value) {
|
|
ESP_LOGD(TAG, "eventPlayRemoteObjectStatus RemoteSPITType: %s RemoteSPITObject: %s Position: %lld Value: %d", p_SPITType.getName().data(), p_SPITObject.getName().data(), p_FrameInsideObject, p_Value);
|
|
}
|
|
|
|
/**
|
|
* Send a remote control command to the SPITServer.<br>
|
|
* There may be different command types:
|
|
* a) Some don't use value e.g. go to next scene, olay a jingle, ..
|
|
* b) Some use values e.g. the main sound fader
|
|
* @param p_SPITObjectID the id of the remote SPITObject (this represents the remote control command)
|
|
* @param p_Valueppm the value in ppm <br>
|
|
* in case a) the value is ignored<br>
|
|
* in case b) the value is used
|
|
* @param p_ValueFlag indicates how the server should use p_Valueppm:<br>
|
|
* VALUEFLAG_DIRECT (0x00) The server will overwrite his existing value with p_Value<br>
|
|
* VALUEFLAG_INCREASE (0x01) The server increases his existing value by p_Valueppm
|
|
* VALUEFLAG_DECREASE (0x01) The server decreases his existing value by p_Valueppm
|
|
*/
|
|
void MyApp::sendRemoteObject(string p_SPITObjectID, int p_Valueppm, char p_ValueFlag) {
|
|
if (m_SPIT_Client != NULL) {
|
|
m_SPIT_Client->sendRemoteObject(p_SPITObjectID, p_Valueppm, p_ValueFlag);
|
|
}
|
|
}
|
|
|
|
//liveSHOWsoftware excample for sending remote control
|
|
//the liveSHOW software has the remote control commands (SPITObjects) among other things:
|
|
// + next secenebridge with id "nextSceneBridge"
|
|
// + main mixer sound width id = "mainmixerSound_Volume00"
|
|
//You can detect this in eventSPITObjectRemote(...)
|
|
void MyApp::testLiveShowRemote() {
|
|
//We jump to the next Scenebridge - no Value is needed
|
|
m_SPIT_Client->sendRemoteObject("nextSceneBridge");
|
|
//we set the main sound volume to 0.1, SPIT uses ppm -> 0.1 = 100000
|
|
m_SPIT_Client->sendRemoteObject("mainmixerSound_Volume00", 100000, SPIT_Client::VALUEFLAG_DIRECT);
|
|
//we increase the main sound volume by 0.1, SPIT uses ppm -> 0.1 = 100000
|
|
m_SPIT_Client->sendRemoteObject("mainmixerSound_Volume00", 100000, SPIT_Client::VALUEFLAG_INCREASE);
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------
|
|
//---------- Options for the client user ----------
|
|
//Normally this should not be used, because because the server is master of things
|
|
//In some situations, however, it may be helpful
|
|
|
|
/**
|
|
* Removes the SPITType with id == p_SPITTypeID
|
|
* @param p_SPITTypeID the id of the SPITType
|
|
* @return
|
|
*/
|
|
int MyApp::removeSPITType(string p_SPITTypeID) {
|
|
if (m_SPIT_Client == NULL) return -1;
|
|
return m_SPIT_Client->removeSPITType(p_SPITTypeID);
|
|
}
|
|
/**
|
|
* Removes the SPITObject with id == p_SPITObjectID
|
|
* @param p_SPITObjectID the id of the SPITObject
|
|
* @return
|
|
*/
|
|
int MyApp::removeSPITObject(string p_SPITObjectID) {
|
|
if (m_SPIT_Client == NULL) return -1;
|
|
return m_SPIT_Client->removeSPITObject(p_SPITObjectID);
|
|
}
|
|
/**
|
|
* Changes the SPITType
|
|
* @param p_SPITType a pointer to a SPITType instance whith changed members
|
|
* @return
|
|
*/
|
|
int MyApp::changeSPITType(SPITType* p_SPITType) {
|
|
return m_SPIT_Client->changeSPITType(p_SPITType);
|
|
}
|
|
/**
|
|
* Changes the SPITObject
|
|
* @param p_SPITObject a pointer to a SPITObject with changed members
|
|
* @return
|
|
*/
|
|
int MyApp::changeSPITObject(SPITObject* p_SPITObject) {
|
|
return m_SPIT_Client->changeSPITObject(p_SPITObject);
|
|
}
|