#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(); //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,
//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.
* For this you have to call SPIT_Client::startServerAutoDetect.
* @param p_DetectedServer a reference to a copy of a SAD_DetectedServer instance.
* After this function call the copy of the SAD_DetectedServer will be deleted!!
*/ 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.
* For this you have to call SPIT_Client::startServerAutoDetect.
* This is an information used by autodetection and not by an established connection.
*
* When a connection to a SPITServer is established, the autodetection should be stopped.
* The connection lost event is detected by eventConnectionStatus
*
* @param p_DetectedServer a reference to a copy of a SAD_DetectedServer instance.
* After this function call the copy of the SAD_DetectedServer will be deleted!!
*/ 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
* a) the connection to the server is established.
* b) server load a new project
* c) server saves the project under a new name
* @param p_ProjectID the server project's id
* (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.
* @param p_ProjectID the id of the project
* 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:.
* All SPITTypes and SPITObjects available on the server are transferred in the following.
* Several calls of eventSPITType and eventSPITObject will occur.
* At the end eventEndProjectTransfer is called. */ void MyApp::eventStartProjectTransfer() { ESP_LOGD(TAG, "eventStartProjectTransfer"); } /** * The transfer of the server's SPITTypes and SPITObjects is finished.
* 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.
// 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 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.
* May also occur when the server confirms a SPITType created or changed by the client.
* @param p_New true = server created a new SPITType
* false = server changed a existing SPITType
* @param p_SPITType a reference to a copy of the SPITType instance.
* 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.
* 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
* false = server changed a existing SPITType
* @param p_SPITType a reference to a copy of the SPITType instance.
* 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.
* After this function has been exited the SPITType is emeoved from the SPITType-List and the pointer is deleted.
* 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.
* 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.
* 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.
* 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.
* 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 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.
* May also occur when the server confirms a SPITObject created by the client, what the client should never do!!.
* @param p_New true = server created a new SPITObject
* false = server changed a existing SPITObject
* @param p_SPITType a reference to a copy of the associated SPITType instance.
* The reference is deleted after this function call!! * @param p_SPITObject a reference to a copy of the SPITObject instance.
* 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.
* A Remote SPITObject is used to remote control the SPITServer. * @param p_New true = server created a new remote SPITObject
* false = server changed a existing remote SPITObject
* @param p_SPITType a reference to a copy of the associated SPITType instance.
* The reference is deleted after this function call!! * @param p_SPITObject a reference to a copy of the SPITObject instance.
* 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.
* After this function has been exited the SPITObject is emeoved from the SPITObject-List and the pointer is deleted.
* 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.
* The reference is deleted after this function call!! * @param p_SPITObject a reference to a copy of the SPITObject instance.
* 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.
* 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.
* 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.
* The reference is deleted after this function call!! * @param p_SPITObject a reference to a copy of the SPITObject instance.
* 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.
* You can decide here which action should be done or not.
* * @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:
* frame where the cursor is inside the SPITObject
* whether the player is running or not
* the actual value of the SPITObject (in liveSHOWsoftware objects ma faded in or out or the main value is decreased, ..
*/ 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.
* This allows the Client to adjust its display for the remote command.
* @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.
* 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
* in case a) the value is ignored
* in case b) the value is used * @param p_ValueFlag indicates how the server should use p_Valueppm:
* VALUEFLAG_DIRECT (0x00) The server will overwrite his existing value with p_Value
* 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); }