diff --git a/src/drivers/Qt/NetPlay.cpp b/src/drivers/Qt/NetPlay.cpp index 7b393776..d8988041 100644 --- a/src/drivers/Qt/NetPlay.cpp +++ b/src/drivers/Qt/NetPlay.cpp @@ -26,6 +26,7 @@ #include "../../movie.h" #include "../../debug.h" #include "utils/crc32.h" +#include "utils/timeStamp.h" #include "utils/StringUtils.h" #include "Qt/main.h" #include "Qt/dface.h" @@ -482,6 +483,22 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s } } break; + case NETPLAY_PING_RESP: + { + + netPlayPingResp *ping = static_cast(msgBuf); + ping->toHostByteOrder(); + + FCEU::timeStampRecord ts; + ts.readNew(); + + uint64_t diff = ts.toMilliSeconds() - ping->hostTimeStamp; + + client->recordPingResult( diff ); + + //printf("Ping Latency ms: %llu Avg:%f\n", static_cast(diff), client->getAvgPingDelay()); + } + break; default: printf("Unknown Msg: %08X\n", msgId); break; @@ -494,7 +511,7 @@ void NetPlayServer::update(void) bool shouldRunFrame = false; unsigned int clientMinFrame = 0xFFFFFFFF; unsigned int clientMaxFrame = 0; - const uint32_t maxLead = 5u; + const uint32_t maxLead = maxLeadFrames; const uint32_t currFrame = static_cast(currFrameCounter); const uint32_t leadFrame = currFrame + maxLead; const uint32_t lastFrame = inputFrameBack(); @@ -606,7 +623,40 @@ void NetPlayServer::update(void) } } } + + bool shouldRunPing = (cycleCounter % 120) == 0; + if (shouldRunPing) + { + FCEU::timeStampRecord ts; + ts.readNew(); + + netPlayPingReq ping; + ping.hostTimeStamp = ts.toMilliSeconds(); + ping.toNetworkByteOrder(); + + for (auto it = clientList.begin(); it != clientList.end(); it++) + { + NetPlayClient *client = *it; + + if (client->state > 0) + { + sendMsg( client, &ping, sizeof(ping) ); + } + } + } + + bool shouldFlushOutput = true; + if (shouldFlushOutput) + { + for (auto it = clientList.begin(); it != clientList.end(); it++) + { + NetPlayClient *client = *it; + + client->flushData(); + } + } + cycleCounter++; } //----------------------------------------------------------------------------- //--- NetPlayClient @@ -784,6 +834,30 @@ void NetPlayClient::onSocketError(QAbstractSocket::SocketError error) emit errorOccurred(errorMsg); } //----------------------------------------------------------------------------- +void NetPlayClient::recordPingResult( uint64_t delay_ms ) +{ + pingNumSamples++; + pingDelayLast = delay_ms; + pingDelaySum += delay_ms; +} +//----------------------------------------------------------------------------- +void NetPlayClient::resetPingData() +{ + pingNumSamples = 0; + pingDelayLast = 0; + pingDelaySum = 0; +} +//----------------------------------------------------------------------------- +double NetPlayClient::getAvgPingDelay() +{ + double ms = 0.0; + if (pingNumSamples > 0) + { + ms = static_cast(pingDelaySum) / static_cast(pingNumSamples); + } + return ms; +} +//----------------------------------------------------------------------------- static void clientMessageCallback( void *userData, void *msgBuf, size_t msgSize ) { NetPlayClient *client = static_cast(userData); @@ -821,6 +895,8 @@ void NetPlayClient::update(void) statusMsg.toNetworkByteOrder(); sock->write( reinterpret_cast(&statusMsg), sizeof(statusMsg) ); + + flushData(); } } //----------------------------------------------------------------------------- @@ -995,6 +1071,17 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize ) } } break; + case NETPLAY_PING_REQ: + { + netPlayPingResp pong; + netPlayPingReq *ping = static_cast(msgBuf); + ping->toHostByteOrder(); + + pong.hostTimeStamp = ping->hostTimeStamp; + pong.toNetworkByteOrder(); + sock->write( (const char*)&pong, sizeof(netPlayPingResp) ); + } + break; default: printf("Unknown Msg: %08X\n", msgId); break; diff --git a/src/drivers/Qt/NetPlay.h b/src/drivers/Qt/NetPlay.h index acb03f1f..2abc3a94 100644 --- a/src/drivers/Qt/NetPlay.h +++ b/src/drivers/Qt/NetPlay.h @@ -119,6 +119,9 @@ class NetPlayServer : public QTcpServer void setRole(int _role); bool claimRole(NetPlayClient* client, int _role); + uint32_t getMaxLeadFrames(){ return maxLeadFrames; } + void setMaxLeadFrames(uint32_t value){ maxLeadFrames = value; } + void serverProcessMessage( NetPlayClient *client, void *msgBuf, size_t msgSize ); QString sessionName; @@ -135,6 +138,8 @@ class NetPlayServer : public QTcpServer int roleMask = 0; NetPlayClient* clientPlayer[4] = { nullptr }; int forceResyncCount = 10; + uint32_t cycleCounter = 0; + uint32_t maxLeadFrames = 10u; public slots: void newConnectionRdy(void); @@ -209,6 +214,9 @@ class NetPlayClient : public QObject bool shouldDestroy(){ return needsDestroy; } bool isPaused(){ return paused; } void setPaused(bool value){ paused = value; } + void recordPingResult( uint64_t delay_ms ); + void resetPingData(void); + double getAvgPingDelay(); QString userName; QString password; @@ -234,6 +242,10 @@ class NetPlayClient : public QObject bool _connected = false; bool paused = false; + uint64_t pingDelaySum = 0; + uint64_t pingDelayLast = 0; + uint64_t pingNumSamples = 0; + std::list input; FCEU::mutex inputMtx; diff --git a/src/drivers/Qt/NetPlayMsgDef.h b/src/drivers/Qt/NetPlayMsgDef.h index 89fb255e..49d1a860 100644 --- a/src/drivers/Qt/NetPlayMsgDef.h +++ b/src/drivers/Qt/NetPlayMsgDef.h @@ -22,6 +22,8 @@ enum netPlayMsgType NETPLAY_RUN_FRAME_REQ, NETPLAY_CLIENT_STATE, NETPLAY_ERROR_MSG, + NETPLAY_PING_REQ, + NETPLAY_PING_RESP, }; enum netPlayerId @@ -269,5 +271,53 @@ struct netPlayClientState } }; +struct netPlayPingReq +{ + netPlayMsgHdr hdr; + + uint64_t hostTimeStamp; + + netPlayPingReq(void) + : hdr(NETPLAY_PING_REQ, sizeof(netPlayPingReq)), hostTimeStamp(0) + { + } + + void toHostByteOrder() + { + hdr.toHostByteOrder(); + hostTimeStamp = netPlayByteSwap(hostTimeStamp); + } + + void toNetworkByteOrder() + { + hdr.toNetworkByteOrder(); + hostTimeStamp = netPlayByteSwap(hostTimeStamp); + } +}; + +struct netPlayPingResp +{ + netPlayMsgHdr hdr; + + uint64_t hostTimeStamp; + + netPlayPingResp(void) + : hdr(NETPLAY_PING_RESP, sizeof(netPlayPingResp)), hostTimeStamp(0) + { + } + + void toHostByteOrder() + { + hdr.toHostByteOrder(); + hostTimeStamp = netPlayByteSwap(hostTimeStamp); + } + + void toNetworkByteOrder() + { + hdr.toNetworkByteOrder(); + hostTimeStamp = netPlayByteSwap(hostTimeStamp); + } +}; + #pragma pack(pop)