diff options
Diffstat (limited to 'LibOVR/Src/Service')
-rw-r--r-- | LibOVR/Src/Service/Service_NetClient.cpp | 882 | ||||
-rw-r--r-- | LibOVR/Src/Service/Service_NetClient.h | 149 | ||||
-rw-r--r-- | LibOVR/Src/Service/Service_NetSessionCommon.cpp | 343 | ||||
-rw-r--r-- | LibOVR/Src/Service/Service_NetSessionCommon.h | 142 |
4 files changed, 1516 insertions, 0 deletions
diff --git a/LibOVR/Src/Service/Service_NetClient.cpp b/LibOVR/Src/Service/Service_NetClient.cpp new file mode 100644 index 0000000..c6af2cd --- /dev/null +++ b/LibOVR/Src/Service/Service_NetClient.cpp @@ -0,0 +1,882 @@ +/************************************************************************************ + +Filename : Service_NetClient.cpp +Content : Client for service interface +Created : June 12, 2014 +Authors : Michael Antonov, Kevin Jenkins, Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#include "Service_NetClient.h" +#include "../Net/OVR_MessageIDTypes.h" + +#if defined (OVR_OS_MAC) || defined(OVR_OS_LINUX) +#define GetCurrentProcessId getpid +#endif +OVR_DEFINE_SINGLETON(OVR::Service::NetClient); + +namespace OVR { namespace Service { + +using namespace OVR::Net; + + +//// NetClient + +NetClient::NetClient() : + LatencyTesterAvailable(false), + HMDCount(0), + EdgeTriggeredHMDCount(false) +{ + GetSession()->AddSessionListener(this); + + // Register RPC functions + registerRPC(); + + Start(); + + // Must be at end of function + PushDestroyCallbacks(); +} + +NetClient::~NetClient() +{ +} + +void NetClient::OnSystemDestroy() +{ + onSystemDestroy(); +} + +void NetClient::OnThreadDestroy() +{ + onThreadDestroy(); +} + +int NetClient::Run() +{ + SetThreadName("NetClient"); + + while (!Terminated) + { + // Note: There is no watchdog here because the watchdog is part of the private code + + GetSession()->Poll(false); + + if (GetSession()->GetActiveSocketsCount() == 0) + { + Thread::MSleep(10); + } + } + + return 0; +} + +void NetClient::OnReceive(ReceivePayload* pPayload, ListenerReceiveResult* lrrOut) +{ + OVR_UNUSED(lrrOut); + OVR_UNUSED(pPayload); +} + +void NetClient::OnDisconnected(Connection* conn) +{ + OVR_UNUSED(conn); + + OVR_DEBUG_LOG(("[NetClient] Disconnected")); + + EdgeTriggeredHMDCount = false; +} + +void NetClient::OnConnected(Connection* conn) +{ + OVR_UNUSED(conn); + + OVR_DEBUG_LOG(("[NetClient] Connected to a server running version %d.%d.%d (my version=%d.%d.%d)", + conn->RemoteMajorVersion, conn->RemoteMinorVersion, conn->RemotePatchVersion, + RPCVersion_Major, RPCVersion_Minor, RPCVersion_Patch)); + + EdgeTriggeredHMDCount = false; +} + +bool NetClient::Connect(bool blocking) +{ + // Set up bind parameters + OVR::Net::BerkleyBindParameters bbp; + bbp.Address = "::1"; // Bind to localhost only! + bbp.blockingTimeout = 5000; + OVR::Net::SockAddr sa; + sa.Set("::1", VRServicePort, SOCK_STREAM); + + // Attempt to connect + OVR::Net::SessionResult result = GetSession()->ConnectPTCP(&bbp, &sa, blocking); + + // Already connected counts as success too + return result == Net::SessionResult_OK || + result == Net::SessionResult_AlreadyConnected || + result == Net::SessionResult_ConnectInProgress; +} + +void NetClient::Disconnect() +{ + GetSession()->Shutdown(); +} + +bool NetClient::IsConnected(bool attemptReconnect, bool blockOnReconnect) +{ + // If it was able to connect, + if (GetSession()->GetConnectionCount() > 0) + { + return true; + } + else if (attemptReconnect) + { + // Attempt to connect here + Connect(blockOnReconnect); + + // If it connected, + if (GetSession()->GetConnectionCount() > 0) + { + return true; + } + } + + // No connections + return false; +} + +void NetClient::GetLocalProtocolVersion(int& major, int& minor, int& patch) +{ + major = RPCVersion_Major; + minor = RPCVersion_Minor; + patch = RPCVersion_Patch; +} + +bool NetClient::GetRemoteProtocolVersion(int& major, int& minor, int& patch) +{ + Ptr<Connection> conn = GetSession()->GetConnectionAtIndex(0); + + if (conn) + { + major = conn->RemoteMajorVersion; + minor = conn->RemoteMinorVersion; + patch = conn->RemotePatchVersion; + return true; + } + + return false; +} + + +//// NetClient API + +const char* NetClient::GetStringValue(VirtualHmdId hmd, const char* key, const char* default_val) +{ + if (!IsConnected(true, true)) + { + return ""; + } + + // If a null value is provided, + if (!default_val) + { + default_val = ""; + } + + ProfileGetValue1_Str = default_val; + + OVR::Net::BitStream bsOut, returnData; + bsOut.Write(hmd); + bsOut.Write(key); + bsOut.Write(default_val); + if (!GetRPC1()->CallBlocking("GetStringValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return ""; + } + if (!returnData.Read(ProfileGetValue1_Str)) + { + OVR_ASSERT(false); + } + return ProfileGetValue1_Str.ToCStr(); +} +bool NetClient::GetBoolValue(VirtualHmdId hmd, const char* key, bool default_val) +{ + if (!IsConnected(true, true)) + { + return default_val; + } + + OVR::Net::BitStream bsOut, returnData; + bsOut.Write(hmd); + bsOut.Write(key); + bsOut.Write(default_val); + if (!GetRPC1()->CallBlocking("GetBoolValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return default_val; + } + uint8_t out = 0; + if (!returnData.Read(out)) + { + OVR_ASSERT(false); + } + return out != 0; +} +int NetClient::GetIntValue(VirtualHmdId hmd, const char* key, int default_val) +{ + if (!IsConnected(true, true)) + { + return default_val; + } + + OVR::Net::BitStream bsOut, returnData; + bsOut.Write(hmd); + bsOut.Write(key); + bsOut.Write(default_val); + if (!GetRPC1()->CallBlocking("GetIntValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return default_val; + } + int32_t out = (int32_t)default_val; + if (!returnData.Read(out)) + { + OVR_ASSERT(false); + } + return out; +} +double NetClient::GetNumberValue(VirtualHmdId hmd, const char* key, double default_val) +{ + if (!IsConnected(true, true)) + { + return default_val; + } + + OVR::Net::BitStream bsOut, returnData; + bsOut.Write(hmd); + bsOut.Write(key); + bsOut.Write(default_val); + if (!GetRPC1()->CallBlocking("GetNumberValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return default_val; + } + double out = 0.; + returnData.Read(out); + return out; +} +int NetClient::GetNumberValues(VirtualHmdId hmd, const char* key, double* values, int num_vals) +{ + if (!IsConnected(true, true)) + { + return 0; + } + + OVR::Net::BitStream bsOut, returnData; + bsOut.Write(hmd); + bsOut.Write(key); + + int32_t w = (int32_t)num_vals; + bsOut.Write(w); + + if (!GetRPC1()->CallBlocking("GetNumberValues_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return 0; + } + + int32_t out = 0; + if (!returnData.Read(out)) + { + OVR_ASSERT(false); + } + OVR_ASSERT(out >= 0 && out <= num_vals); + if (out < 0) + { + out = 0; + } + else if (out > num_vals) + { + out = num_vals; + } + + for (int i = 0; i < out && i < num_vals; i++) + { + if (!returnData.Read(values[i])) + { + return i; + } + } + + return out; +} + +bool NetClient::SetStringValue(VirtualHmdId hmd, const char* key, const char* val) +{ + if (!IsConnected(true, true)) + { + return false; + } + + OVR::Net::BitStream bsOut; + bsOut.Write(hmd); + bsOut.Write(key); + + bsOut.Write(val); + + if (!GetRPC1()->Signal("SetStringValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0))) + { + return false; + } + + return true; +} + +bool NetClient::SetBoolValue(VirtualHmdId hmd, const char* key, bool val) +{ + if (!IsConnected(true, true)) + { + return false; + } + + OVR::Net::BitStream bsOut; + bsOut.Write(hmd); + bsOut.Write(key); + + uint8_t b = val ? 1 : 0; + bsOut.Write(b); + + if (!GetRPC1()->Signal("SetBoolValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0))) + { + return false; + } + + return true; +} + +bool NetClient::SetIntValue(VirtualHmdId hmd, const char* key, int val) +{ + if (!IsConnected(true, true)) + { + return false; + } + + OVR::Net::BitStream bsOut; + bsOut.Write(hmd); + bsOut.Write(key); + + int32_t w = (int32_t)val; + bsOut.Write(w); + + if (!GetRPC1()->Signal("SetIntValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0))) + { + return false; + } + + return true; +} + +bool NetClient::SetNumberValue(VirtualHmdId hmd, const char* key, double val) +{ + if (!IsConnected(true, true)) + { + return false; + } + + OVR::Net::BitStream bsOut; + bsOut.Write(hmd); + bsOut.Write(key); + + bsOut.Write(val); + + if (!GetRPC1()->Signal("SetNumberValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0))) + { + return false; + } + + return true; +} + +bool NetClient::SetNumberValues(VirtualHmdId hmd, const char* key, const double* vals, int num_vals) +{ + if (!IsConnected(true, true)) + { + return false; + } + + OVR::Net::BitStream bsOut; + bsOut.Write(hmd); + bsOut.Write(key); + + int32_t w_count = (int32_t)num_vals; + bsOut.Write(w_count); + + for (int i = 0; i < num_vals; i++) + { + bsOut.Write(vals[i]); + } + + if (!GetRPC1()->Signal("SetNumberValues_1", &bsOut, GetSession()->GetConnectionAtIndex(0))) + { + return false; + } + + return true; +} + +int NetClient::Hmd_Detect() +{ + if (!IsConnected(true, false)) + { + return 0; + } + + // If using edge-triggered HMD counting, + if (EdgeTriggeredHMDCount) + { + // Return the last update from the server + return HMDCount; + } + + // Otherwise: We need to ask the first time + + OVR::Net::BitStream bsOut, returnData; + + if (!GetRPC1()->CallBlocking("Hmd_Detect_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return 0; + } + + int32_t out = 0; + if (!returnData.Read(out)) + { + OVR_ASSERT(false); + } + HMDCount = out; + EdgeTriggeredHMDCount = true; + return out; +} + +bool NetClient::Hmd_Create(int index, HMDNetworkInfo* netInfo) +{ + if (!IsConnected(true, true)) + { + return false; + } + + OVR::Net::BitStream bsOut, returnData; + + int32_t w = (int32_t)index; + bsOut.Write(w); + + // Need the Pid for driver mode + pid_t pid = GetCurrentProcessId(); + bsOut.Write(pid); + + if (!GetRPC1()->CallBlocking("Hmd_Create_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return false; + } + + return netInfo->Deserialize(&returnData); +} + +bool NetClient::GetDriverMode(bool& driverInstalled, bool& compatMode, bool& hideDK1Mode) +{ + if (!IsConnected(true, true)) + { + return false; + } + + OVR::Net::BitStream bsOut, returnData; + + bsOut.Write(InvalidVirtualHmdId); + + if (!GetRPC1()->CallBlocking("GetDriverMode_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return false; + } + + int32_t w_driverInstalled = 0; + int32_t w_compatMode = 0; + int32_t w_hideDK1Mode = 0; + returnData.Read(w_driverInstalled); + returnData.Read(w_compatMode); + if (!returnData.Read(w_hideDK1Mode)) + { + return false; + } + + driverInstalled = w_driverInstalled != 0; + compatMode = w_compatMode != 0; + hideDK1Mode = w_hideDK1Mode != 0; + return true; +} + +bool NetClient::SetDriverMode(bool compatMode, bool hideDK1Mode) +{ + if (!IsConnected(true, true)) + { + return false; + } + + OVR::Net::BitStream bsOut, returnData; + + bsOut.Write(InvalidVirtualHmdId); + + int32_t w_compatMode, w_hideDK1Mode; + w_compatMode = compatMode ? 1 : 0; + w_hideDK1Mode = hideDK1Mode ? 1 : 0; + bsOut.Write(w_compatMode); + bsOut.Write(w_hideDK1Mode); + + if (!GetRPC1()->CallBlocking("SetDriverMode_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return false; + } + + int32_t out = 0; + if (!returnData.Read(out)) + { + OVR_ASSERT(false); + return false; + } + + return out != 0; +} + +bool NetClient::Hmd_AttachToWindow(VirtualHmdId hmd, void* hWindow) +{ + if (!IsConnected(false, false)) + { + return false; + } + + OVR::Net::BitStream bsOut; + bsOut.Write(hmd); + + #ifdef OVR_OS_LINUX + if (hWindow == NULL) + { + return false; + } + unsigned long hWinWord = *(unsigned long *)hWindow; + #else + UInt64 hWinWord = (UPInt)hWindow; + #endif + bsOut.Write(hWinWord); + + if (!GetRPC1()->CallBlocking("Hmd_AttachToWindow_1", &bsOut, GetSession()->GetConnectionAtIndex(0))) + { + return false; + } + + return true; +} + +void NetClient::Hmd_Release(VirtualHmdId hmd) +{ + if (!IsConnected(false, false)) + { + return; + } + + OVR::Net::BitStream bsOut; + bsOut.Write(hmd); + bool result = GetRPC1()->CallBlocking("Hmd_Release_1", &bsOut, GetSession()->GetConnectionAtIndex(0)); + OVR_ASSERT_AND_UNUSED(result, result); +} + +void NetClient::SetLastError(String str) +{ + Hmd_GetLastError_Str = str; +} + +// Last string is cached locally. +const char* NetClient::Hmd_GetLastError(VirtualHmdId hmd) +{ + if (hmd == InvalidVirtualHmdId || !IsConnected(false, false)) + { + return Hmd_GetLastError_Str.ToCStr(); + } + + OVR::Net::BitStream bsOut, returnData; + bsOut.Write(hmd); + if (!GetRPC1()->CallBlocking("Hmd_GetLastError_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return Hmd_GetLastError_Str.ToCStr(); + } + if (!returnData.Read(Hmd_GetLastError_Str)) + { + OVR_ASSERT(false); + } + return Hmd_GetLastError_Str.ToCStr(); +} + + +// Fills in description about HMD; this is the same as filled in by ovrHmd_Create. +// The actual descriptor is a par +bool NetClient::Hmd_GetHmdInfo(VirtualHmdId hmd, HMDInfo* hmdInfo) +{ + if (!IsConnected(false, false)) + { + return false; + } + + OVR::Net::BitStream bsOut, returnData; + bsOut.Write(hmd); + if (!GetRPC1()->CallBlocking("Hmd_GetHmdInfo_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return false; + } + + return NetSessionCommon::DeserializeHMDInfo(&returnData, hmdInfo); +} + + +//------------------------------------------------------------------------------------- +unsigned int NetClient::Hmd_GetEnabledCaps(VirtualHmdId hmd) +{ + if (!IsConnected(false, false)) + { + return 0; + } + + OVR::Net::BitStream bsOut, returnData; + bsOut.Write(hmd); + if (!GetRPC1()->CallBlocking("Hmd_GetEnabledCaps_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return 0; + } + + uint32_t c = 0; + if (!returnData.Read(c)) + { + OVR_ASSERT(false); + } + return c; +} + +// Returns new caps after modification +unsigned int NetClient::Hmd_SetEnabledCaps(VirtualHmdId hmd, unsigned int hmdCaps) +{ + if (!IsConnected(false, false)) + { + return 0; + } + + OVR::Net::BitStream bsOut, returnData; + bsOut.Write(hmd); + + uint32_t c = (uint32_t)hmdCaps; + bsOut.Write(c); + + if (!GetRPC1()->CallBlocking("Hmd_SetEnabledCaps_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return 0; + } + + c = 0; + if (!returnData.Read(c)) + { + OVR_ASSERT(false); + } + return c; +} + + +//------------------------------------------------------------------------------------- +// *** Tracking Setup + +bool NetClient::Hmd_ConfigureTracking(VirtualHmdId hmd, unsigned supportedCaps, unsigned requiredCaps) +{ + if (!IsConnected(false, false)) + { + return false; + } + + OVR::Net::BitStream bsOut, returnData; + bsOut.Write(hmd); + + uint32_t w_sc = supportedCaps; + bsOut.Write(w_sc); + uint32_t w_rc = requiredCaps; + bsOut.Write(w_rc); + + if (!GetRPC1()->CallBlocking("Hmd_ConfigureTracking_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return false; + } + + uint8_t b; + if (!returnData.Read(b)) + { + OVR_ASSERT(false); + } + + return b != 0; +} + + +void NetClient::Hmd_ResetTracking(VirtualHmdId hmd) +{ + if (!IsConnected(false, false)) + { + return; + } + + OVR::Net::BitStream bsOut; + bsOut.Write(hmd); + if (!GetRPC1()->CallBlocking("Hmd_ResetTracking_1", &bsOut, GetSession()->GetConnectionAtIndex(0))) + { + return; + } +} + +bool NetClient::LatencyUtil_ProcessInputs(double startTestSeconds, unsigned char rgbColorOut[3]) +{ + if (!IsConnected(false, false)) + { + return false; + } + + if (!LatencyTesterAvailable) + { + return false; + } + + OVR::Net::BitStream bsOut, returnData; + bsOut.Write(startTestSeconds); + if (!GetRPC1()->CallBlocking("LatencyUtil_ProcessInputs_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return false; + } + + uint8_t u; + returnData.Read(u); + rgbColorOut[0] = u; + returnData.Read(u); + rgbColorOut[1] = u; + if (!returnData.Read(u)) + { + return false; + } + rgbColorOut[2] = u; + + return true; +} + +const char* NetClient::LatencyUtil_GetResultsString() +{ + if (!IsConnected(false, false)) + { + return NULL; + } + + OVR::Net::BitStream bsOut, returnData; + if (!GetRPC1()->CallBlocking("LatencyUtil_GetResultsString_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData)) + { + return NULL; + } + + if (!returnData.Read(LatencyUtil_GetResultsString_Str)) + { + OVR_ASSERT(false); + } + + return LatencyUtil_GetResultsString_Str.ToCStr(); +} + +bool NetClient::ShutdownServer() +{ + if (!IsConnected(false, false)) + { + return false; + } + + OVR::Net::BitStream bsOut; + GetRPC1()->BroadcastSignal("Shutdown_1", &bsOut); + + return true; +} + + +//// Push Notifications: + +void NetClient::registerRPC() +{ +#define RPC_REGISTER_SLOT(observerScope, functionName) \ + observerScope.SetHandler(OVR::Net::Plugins::RPCSlot::FromMember<NetClient, &NetClient::functionName>(this)); pRPC->RegisterSlot(OVR_STRINGIZE(functionName), observerScope); + + // Register RPC functions: + RPC_REGISTER_SLOT(InitialServerStateScope, InitialServerState_1); + RPC_REGISTER_SLOT(LatencyTesterAvailableScope, LatencyTesterAvailable_1); + RPC_REGISTER_SLOT(DefaultLogOutputScope, DefaultLogOutput_1); + RPC_REGISTER_SLOT(HMDCountUpdateScope, HMDCountUpdate_1); +} + +void NetClient::InitialServerState_1(BitStream* userData, ReceivePayload* pPayload) +{ + LatencyTesterAvailable_1(userData, pPayload); +} + +void NetClient::LatencyTesterAvailable_1(BitStream* userData, ReceivePayload* pPayload) +{ + OVR_UNUSED(pPayload); + + uint8_t b = 0; + if (!userData->Read(b)) + { + OVR_ASSERT(false); + return; + } + + LatencyTesterAvailable = (b != 0); +} + +void NetClient::DefaultLogOutput_1(BitStream* userData, ReceivePayload* pPayload) +{ + OVR_UNUSED(pPayload); + + String formattedText; + LogMessageType messageType = Log_Text; // Will normally be overwritten below. + userData->Read(messageType); + if (userData->Read(formattedText)) + { + if (OVR::Log::GetGlobalLog()) + { + OVR::String logStr = "[From Service] "; + logStr.AppendString(formattedText); + OVR::Log::GetGlobalLog()->LogMessage(messageType, "%s", logStr.ToCStr()); + } + } +} + +void NetClient::HMDCountUpdate_1(BitStream* userData, ReceivePayload* pPayload) +{ + OVR_UNUSED(pPayload); + + int32_t hmdCount = 0; + if (!userData->Read(hmdCount)) + { + OVR_ASSERT(false); + return; + } + + HMDCount = hmdCount; + EdgeTriggeredHMDCount = true; +} + + +}} // namespace OVR::Service diff --git a/LibOVR/Src/Service/Service_NetClient.h b/LibOVR/Src/Service/Service_NetClient.h new file mode 100644 index 0000000..ab7906e --- /dev/null +++ b/LibOVR/Src/Service/Service_NetClient.h @@ -0,0 +1,149 @@ +/************************************************************************************ + +Filename : Service_NetClient.h +Content : Client for service interface +Created : June 12, 2014 +Authors : Michael Antonov, Kevin Jenkins, Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#ifndef OVR_Service_NetClient_h +#define OVR_Service_NetClient_h + +#include "../Net/OVR_NetworkTypes.h" +#include "Service_NetSessionCommon.h" +#include "../Kernel/OVR_System.h" +#include "../OVR_CAPI.h" +#include "../Util/Util_Render_Stereo.h" + +namespace OVR { namespace Service { + +using namespace OVR::Net; + + +//------------------------------------------------------------------------------------- +// NetClient + +class NetClient : public NetSessionCommon, + public Net::Plugins::NetworkPlugin, + public SystemSingletonBase<NetClient> +{ + OVR_DECLARE_SINGLETON(NetClient); + virtual void OnThreadDestroy(); + + // Status + bool LatencyTesterAvailable; + int HMDCount; + bool EdgeTriggeredHMDCount; + + virtual void OnReceive(Net::ReceivePayload* pPayload, Net::ListenerReceiveResult* lrrOut); + virtual void OnDisconnected(Net::Connection* conn); + virtual void OnConnected(Net::Connection* conn); + + virtual int Run(); + +public: + bool Connect(bool blocking); + bool IsConnected(bool attemptReconnect, bool blockOnReconnect); + void Disconnect(); + + void GetLocalProtocolVersion(int& major, int& minor, int& patch); + // This function may fail if it is not connected + bool GetRemoteProtocolVersion(int& major, int& minor, int& patch); + + void SetLastError(String str); + +public: + // Persistent key-value storage + const char* GetStringValue(VirtualHmdId hmd, const char* key, const char* default_val); + bool GetBoolValue(VirtualHmdId hmd, const char* key, bool default_val); + int GetIntValue(VirtualHmdId hmd, const char* key, int default_val); + double GetNumberValue(VirtualHmdId hmd, const char* key, double default_val); + int GetNumberValues(VirtualHmdId hmd, const char* key, double* values, int num_vals); + + bool SetStringValue(VirtualHmdId hmd, const char* key, const char* val); + bool SetBoolValue(VirtualHmdId hmd, const char* key, bool val); + bool SetIntValue(VirtualHmdId hmd, const char* key, int val); + bool SetNumberValue(VirtualHmdId hmd, const char* key, double val); + bool SetNumberValues(VirtualHmdId hmd, const char* key, const double* vals, int num_vals); + + bool GetDriverMode(bool& driverInstalled, bool& compatMode, bool& hideDK1Mode); + bool SetDriverMode(bool compatMode, bool hideDK1Mode); + + int Hmd_Detect(); + bool Hmd_Create(int index, HMDNetworkInfo* netInfo); + void Hmd_Release(VirtualHmdId hmd); + + // Last string is cached locally. + const char* Hmd_GetLastError(VirtualHmdId hmd); + + // TBD: Replace with a function to return internal, original HMDInfo? + + // Fills in description about HMD; this is the same as filled in by ovrHmd_Create. + // The actual descriptor is a par + bool Hmd_GetHmdInfo(VirtualHmdId hmd, HMDInfo* hmdInfo); + + //------------------------------------------------------------------------------------- + unsigned int Hmd_GetEnabledCaps(VirtualHmdId hmd); + // Returns new caps after modification + unsigned int Hmd_SetEnabledCaps(VirtualHmdId hmd, unsigned int hmdCaps); + + // Updates driver render target + bool Hmd_AttachToWindow(VirtualHmdId hmd, void* hWindow); + + //------------------------------------------------------------------------------------- + // *** Tracking Setup + + bool Hmd_ConfigureTracking(VirtualHmdId hmd, unsigned supportedCaps, unsigned requiredCaps); + void Hmd_ResetTracking(VirtualHmdId hmd); + + // TBD: Camera frames + bool LatencyUtil_ProcessInputs(double startTestSeconds, unsigned char rgbColorOut[3]); + const char* LatencyUtil_GetResultsString(); + + bool ShutdownServer(); + +protected: + String Hmd_GetLastError_Str; + String LatencyUtil_GetResultsString_Str; + String ProfileGetValue1_Str, ProfileGetValue3_Str; + +protected: + //// Push Notifications: + + void registerRPC(); + + ObserverScope<Net::Plugins::RPCSlot> InitialServerStateScope; + void InitialServerState_1(BitStream* userData, ReceivePayload* pPayload); + + ObserverScope<Net::Plugins::RPCSlot> LatencyTesterAvailableScope; + void LatencyTesterAvailable_1(BitStream* userData, ReceivePayload* pPayload); + + ObserverScope<Net::Plugins::RPCSlot> DefaultLogOutputScope; + void DefaultLogOutput_1(BitStream* userData, ReceivePayload* pPayload); + + ObserverScope<Net::Plugins::RPCSlot> HMDCountUpdateScope; + void HMDCountUpdate_1(BitStream* userData, ReceivePayload* pPayload); +}; + + +}} // namespace OVR::Service + +#endif // OVR_Service_NetClient_h diff --git a/LibOVR/Src/Service/Service_NetSessionCommon.cpp b/LibOVR/Src/Service/Service_NetSessionCommon.cpp new file mode 100644 index 0000000..ba2c773 --- /dev/null +++ b/LibOVR/Src/Service/Service_NetSessionCommon.cpp @@ -0,0 +1,343 @@ +/************************************************************************************ + +Filename : Service_NetSessionCommon.cpp +Content : Server for service interface +Created : June 12, 2014 +Authors : Kevin Jenkins, Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#include "Service_NetSessionCommon.h" +#include "../OVR_Stereo.h" + +namespace OVR { namespace Service { + + +//// NetSessionCommon + +NetSessionCommon::NetSessionCommon() : + Terminated(false) +{ + pSession = new Net::Session; + OVR_ASSERT(pSession != NULL); + + pRPC = new Net::Plugins::RPC1; + OVR_ASSERT(pRPC != NULL); + + pSession->AddSessionListener(pRPC); +} + +NetSessionCommon::~NetSessionCommon() +{ + if (pSession) + { + delete pSession; + pSession = NULL; + } + if (pRPC) + { + delete pRPC; + pRPC = NULL; + } + + Terminated = true; + + OVR_ASSERT(IsFinished()); +} + +void NetSessionCommon::onSystemDestroy() +{ + Terminated = true; + + Join(); + + Release(); +} + +void NetSessionCommon::onThreadDestroy() +{ + Terminated = true; + if (pSession) + { + pSession->Shutdown(); + } +} + +void NetSessionCommon::SerializeHMDInfo(Net::BitStream *bitStream, HMDInfo* hmdInfo) +{ + bitStream->Write(hmdInfo->ProductName); + bitStream->Write(hmdInfo->Manufacturer); + + int32_t w = hmdInfo->Version; + bitStream->Write(w); + + w = hmdInfo->HmdType; + bitStream->Write(w); + + w = hmdInfo->ResolutionInPixels.w; + bitStream->Write(w); + + w = hmdInfo->ResolutionInPixels.h; + bitStream->Write(w); + + w = hmdInfo->ShimInfo.DeviceNumber; + bitStream->Write(w); + + w = hmdInfo->ShimInfo.NativeWidth; + bitStream->Write(w); + + w = hmdInfo->ShimInfo.NativeHeight; + bitStream->Write(w); + + w = hmdInfo->ShimInfo.Rotation; + bitStream->Write(w); + + bitStream->Write(hmdInfo->ScreenSizeInMeters.w); + bitStream->Write(hmdInfo->ScreenSizeInMeters.h); + bitStream->Write(hmdInfo->ScreenGapSizeInMeters); + bitStream->Write(hmdInfo->CenterFromTopInMeters); + bitStream->Write(hmdInfo->LensSeparationInMeters); + + w = hmdInfo->DesktopX; + bitStream->Write(w); + + w = hmdInfo->DesktopY; + bitStream->Write(w); + + w = hmdInfo->Shutter.Type; + bitStream->Write(w); + + bitStream->Write(hmdInfo->Shutter.VsyncToNextVsync); + bitStream->Write(hmdInfo->Shutter.VsyncToFirstScanline); + bitStream->Write(hmdInfo->Shutter.FirstScanlineToLastScanline); + bitStream->Write(hmdInfo->Shutter.PixelSettleTime); + bitStream->Write(hmdInfo->Shutter.PixelPersistence); + bitStream->Write(hmdInfo->DisplayDeviceName); + + w = hmdInfo->DisplayId; + bitStream->Write(w); + + bitStream->Write(hmdInfo->PrintedSerial); + + uint8_t b = hmdInfo->InCompatibilityMode ? 1 : 0; + bitStream->Write(b); + + w = hmdInfo->VendorId; + bitStream->Write(w); + + w = hmdInfo->ProductId; + bitStream->Write(w); + + bitStream->Write(hmdInfo->CameraFrustumFarZInMeters); + bitStream->Write(hmdInfo->CameraFrustumHFovInRadians); + bitStream->Write(hmdInfo->CameraFrustumNearZInMeters); + bitStream->Write(hmdInfo->CameraFrustumVFovInRadians); + + w = hmdInfo->FirmwareMajor; + bitStream->Write(w); + + w = hmdInfo->FirmwareMinor; + bitStream->Write(w); + + bitStream->Write(hmdInfo->PelOffsetR.x); + bitStream->Write(hmdInfo->PelOffsetR.y); + bitStream->Write(hmdInfo->PelOffsetB.x); + bitStream->Write(hmdInfo->PelOffsetB.y); + + // Important please read before modifying! + // ---------------------------------------------------- + // Please add new serialized data to the end, here. + // Otherwise we will break backwards compatibility + // and e.g. 0.4.4 runtime will not work with 0.4.3 SDK. + + // Please also update the DeserializeHMDInfo() function + // below also and make sure that the members you added + // are initialized properly in the HMDInfo constructor. + + // Note that whenever new fields are added here you + // should also update the minor version of the RPC + // protocol in OVR_Session.h so that clients fail at + // a version check instead of when this data is + // found to be truncated from the server. +} + +bool NetSessionCommon::DeserializeHMDInfo(Net::BitStream *bitStream, HMDInfo* hmdInfo) +{ + bitStream->Read(hmdInfo->ProductName); + bitStream->Read(hmdInfo->Manufacturer); + + int32_t w = 0; + if (!bitStream->Read(w)) + { + // This indicates that no HMD could be found + return false; + } + hmdInfo->Version = w; + + bitStream->Read(w); + hmdInfo->HmdType = (HmdTypeEnum)w; + + bitStream->Read(w); + hmdInfo->ResolutionInPixels.w = w; + + bitStream->Read(w); + hmdInfo->ResolutionInPixels.h = w; + + bitStream->Read(w); + hmdInfo->ShimInfo.DeviceNumber = w; + + bitStream->Read(w); + hmdInfo->ShimInfo.NativeWidth = w; + + bitStream->Read(w); + hmdInfo->ShimInfo.NativeHeight = w; + + bitStream->Read(w); + hmdInfo->ShimInfo.Rotation = w; + + bitStream->Read(hmdInfo->ScreenSizeInMeters.w); + bitStream->Read(hmdInfo->ScreenSizeInMeters.h); + bitStream->Read(hmdInfo->ScreenGapSizeInMeters); + bitStream->Read(hmdInfo->CenterFromTopInMeters); + bitStream->Read(hmdInfo->LensSeparationInMeters); + + bitStream->Read(w); + hmdInfo->DesktopX = w; + + bitStream->Read(w); + hmdInfo->DesktopY = w; + + bitStream->Read(w); + hmdInfo->Shutter.Type = (HmdShutterTypeEnum)w; + + bitStream->Read(hmdInfo->Shutter.VsyncToNextVsync); + bitStream->Read(hmdInfo->Shutter.VsyncToFirstScanline); + bitStream->Read(hmdInfo->Shutter.FirstScanlineToLastScanline); + bitStream->Read(hmdInfo->Shutter.PixelSettleTime); + bitStream->Read(hmdInfo->Shutter.PixelPersistence); + bitStream->Read(hmdInfo->DisplayDeviceName); + + bitStream->Read(w); + hmdInfo->DisplayId = w; + + bitStream->Read(hmdInfo->PrintedSerial); + + uint8_t b = 0; + bitStream->Read(b); + hmdInfo->InCompatibilityMode = (b != 0); + + bitStream->Read(w); + hmdInfo->VendorId = w; + + bitStream->Read(w); + hmdInfo->ProductId = w; + + bitStream->Read(hmdInfo->CameraFrustumFarZInMeters); + bitStream->Read(hmdInfo->CameraFrustumHFovInRadians); + bitStream->Read(hmdInfo->CameraFrustumNearZInMeters); + bitStream->Read(hmdInfo->CameraFrustumVFovInRadians); + + bitStream->Read(w); + hmdInfo->FirmwareMajor = w; + + if (!bitStream->Read(w)) + { + OVR_ASSERT(false); + return false; + } + hmdInfo->FirmwareMinor = w; + + bitStream->Read(hmdInfo->PelOffsetR.x); + bitStream->Read(hmdInfo->PelOffsetR.y); + bitStream->Read(hmdInfo->PelOffsetB.x); + if (!bitStream->Read(hmdInfo->PelOffsetB.y)) + { + OVR_ASSERT(false); + return false; + } + + // Important please read before modifying! + // ---------------------------------------------------- + // Please add new serialized data to the end, here. + // Otherwise we will break backwards compatibility + // and e.g. 0.4.4 runtime will not work with 0.4.3 SDK. + + // Be sure to check that the very last one read properly + // since HMD Info truncation should be caught here. + + return true; +} + +// Prefix key names with this to pass through to server +static const char* BypassPrefix = "server:"; + +static const char* KeyNames[][NetSessionCommon::ENumTypes] = { + /* EGetStringValue */ { "CameraSerial", "CameraUUID", 0 }, + /* EGetBoolValue */ { "ReleaseDK2Sensors", "ReleaseLegacySensors", 0 }, + /* EGetIntValue */ { 0 }, + /* EGetNumberValue */{ "CenterPupilDepth", "LoggingMask", 0 }, + /* EGetNumberValues */{ "NeckModelVector3f", 0 }, + /* ESetStringValue */ { 0 }, + /* ESetBoolValue */ { "ReleaseDK2Sensors", "ReleaseLegacySensors", 0 }, + /* ESetIntValue */ { 0 }, + /* ESetNumberValue */{ "CenterPupilDepth", "LoggingMask", 0 }, + /* ESetNumberValues */{ "NeckModelVector3f", 0 }, +}; + +bool IsInStringArray(const char* a[], const char* key) +{ + for (int i = 0; a[i]; ++i) + { + if (OVR_strcmp(a[i], key) == 0) + return true; + } + + return false; +} + +const char *NetSessionCommon::FilterKeyPrefix(const char* key) +{ + // If key starts with BypassPrefix, + if (strstr(key, BypassPrefix) == key) + { + key += strlen(BypassPrefix); + } + + return key; +} + +bool NetSessionCommon::IsServiceProperty(EGetterSetters e, const char* key) +{ + if ((e >= 0 && e < ENumTypes) && IsInStringArray(KeyNames[e], key)) + { + return true; + } + + // If key starts with BypassPrefix, + if (strstr(key, BypassPrefix) == key) + { + return true; + } + + return false; +} + + +}} // namespace OVR::Service diff --git a/LibOVR/Src/Service/Service_NetSessionCommon.h b/LibOVR/Src/Service/Service_NetSessionCommon.h new file mode 100644 index 0000000..79c0cfb --- /dev/null +++ b/LibOVR/Src/Service/Service_NetSessionCommon.h @@ -0,0 +1,142 @@ +/************************************************************************************ + +Filename : Service_NetSessionCommon.h +Content : Shared networking for service +Created : June 12, 2014 +Authors : Kevin Jenkins, Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#ifndef OVR_Service_NetSessionCommon_h +#define OVR_Service_NetSessionCommon_h + +#include "../OVR_CAPI.h" +#include "../Net/OVR_RPC1.h" +#include "../Kernel/OVR_Threads.h" +#include "../Net/OVR_BitStream.h" +#include "../Kernel/OVR_System.h" + +namespace OVR { + +class HMDInfo; + +namespace Service { + + +//----------------------------------------------------------------------------- +// VirtualHmdId + +// This is an identifier that is unique to each VirtualHmd object on the server +// side. The client side uses this to opaquely reference those objects. + +typedef int32_t VirtualHmdId; +static const int32_t InvalidVirtualHmdId = -1; + +// Localhost-bound TCP port that the service listens on for VR apps +static const int VRServicePort = 30322; // 0x7672 = "vr" little-endian + +// HMDInfo section related to networking +struct HMDNetworkInfo +{ + HMDNetworkInfo() : + NetId(InvalidVirtualHmdId) + { + } + + // Network identifier for HMD + VirtualHmdId NetId; + + // Name of the shared memory object + String SharedMemoryName; + + void Serialize(Net::BitStream* bs) + { + bs->Write(NetId); + bs->Write(SharedMemoryName); + } + bool Deserialize(Net::BitStream* bs) + { + bs->Read(NetId); + return bs->Read(SharedMemoryName); + } +}; + + +//------------------------------------------------------------------------------------- +// ***** NetSessionCommon + +// Common part networking session/RPC implementation shared between client and server. + +class NetSessionCommon : public Thread +{ +protected: + virtual void onSystemDestroy(); + virtual void onThreadDestroy(); + +public: + NetSessionCommon(); + virtual ~NetSessionCommon(); + + Net::Plugins::RPC1* GetRPC1() const + { + return pRPC; + } + Net::Session* GetSession() const + { + return pSession; + } + + static void SerializeHMDInfo(Net::BitStream* bitStream, HMDInfo* hmdInfo); + static bool DeserializeHMDInfo(Net::BitStream* bitStream, HMDInfo* hmdInfo); + +public: + // Getter/setter tools + enum EGetterSetters + { + // Note: If this enumeration changes, then the Servce_NetSessionCommon.cpp + // IsServiceProperty() function should be updated. + + EGetStringValue, + EGetBoolValue, + EGetIntValue, + EGetNumberValue, + EGetNumberValues, + ESetStringValue, + ESetBoolValue, + ESetIntValue, + ESetNumberValue, + ESetNumberValues, + + ENumTypes + }; + + static const char* FilterKeyPrefix(const char* key); + static bool IsServiceProperty(EGetterSetters e, const char* key); + +protected: + bool Terminated; // Thread termination flag + Net::Session* pSession; // Networking session + Net::Plugins::RPC1* pRPC; // Remote procedure calls object +}; + + +}} // namespace OVR::Service + +#endif // OVR_Service_NetSessionCommon_h |