#pragma once #include "RuntimeJson.h" #include "RuntimeCoordinator.h" #include "ShaderTypes.h" #include #include #include #include #include #include #include #include #include class ControlServer; class OpenGLComposite; class OscServer; class RuntimeEventDispatcher; class RuntimeStore; class ControlServices { public: struct AppliedOscUpdate { std::string routeKey; std::string layerKey; std::string parameterKey; JsonValue targetValue; }; struct CompletedOscCommit { std::string routeKey; uint64_t generation = 0; }; explicit ControlServices(RuntimeEventDispatcher& runtimeEventDispatcher); ~ControlServices(); bool Start(OpenGLComposite& composite, RuntimeStore& runtimeStore, std::string& error); void BeginPolling(RuntimeCoordinator& runtimeCoordinator); void Stop(); void BroadcastState(); void RequestBroadcastState(); bool QueueOscUpdate(const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& error); bool ApplyPendingOscUpdates(std::vector& appliedUpdates, std::string& error); bool QueueOscCommit(const std::string& routeKey, const std::string& layerKey, const std::string& parameterKey, const JsonValue& value, uint64_t generation, std::string& error); void ClearOscState(); void ClearOscStateForLayerKey(const std::string& layerKey); void ConsumeCompletedOscCommits(std::vector& completedCommits); private: struct PendingOscUpdate { std::string layerKey; std::string parameterKey; std::string valueJson; }; struct PendingOscCommit { std::string routeKey; std::string layerKey; std::string parameterKey; JsonValue value; uint64_t generation = 0; }; void StartPolling(RuntimeCoordinator& runtimeCoordinator); void StopPolling(); void PollLoop(RuntimeCoordinator& runtimeCoordinator); void WakePolling(); void PublishRuntimeStateBroadcastRequested(const std::string& reason); void PublishOscValueReceived(const PendingOscUpdate& update, const std::string& routeKey); void PublishOscCommitRequested(const PendingOscCommit& commit); void PublishOscOverlaySettled(const PendingOscCommit& commit); std::unique_ptr mControlServer; std::unique_ptr mOscServer; RuntimeEventDispatcher& mRuntimeEventDispatcher; std::thread mPollThread; std::atomic mPollRunning; std::mutex mPollWakeMutex; std::condition_variable mPollWakeCondition; bool mPollWakeRequested = false; std::mutex mPendingOscMutex; std::map mPendingOscUpdates; std::mutex mPendingOscCommitMutex; std::map mPendingOscCommits; std::mutex mCompletedOscCommitMutex; std::vector mCompletedOscCommits; };