#include "RuntimeStatePresenter.h" #include "RuntimeStateJson.h" #include "RuntimeStore.h" #include std::string RuntimeStatePresenter::BuildRuntimeStateJson(const RuntimeStore& runtimeStore) { return SerializeJson(BuildRuntimeStateValue(runtimeStore), true); } JsonValue RuntimeStatePresenter::BuildRuntimeStateValue(const RuntimeStore& runtimeStore) { const HealthTelemetry::Snapshot telemetrySnapshot = runtimeStore.mHealthTelemetry.GetSnapshot(); std::lock_guard lock(runtimeStore.mMutex); JsonValue root = JsonValue::MakeObject(); JsonValue app = JsonValue::MakeObject(); app.set("serverPort", JsonValue(static_cast(runtimeStore.mServerPort))); app.set("oscPort", JsonValue(static_cast(runtimeStore.mConfigStore.GetConfig().oscPort))); app.set("oscBindAddress", JsonValue(runtimeStore.mConfigStore.GetConfig().oscBindAddress)); app.set("oscSmoothing", JsonValue(runtimeStore.mConfigStore.GetConfig().oscSmoothing)); app.set("autoReload", JsonValue(runtimeStore.mAutoReloadEnabled)); app.set("maxTemporalHistoryFrames", JsonValue(static_cast(runtimeStore.mConfigStore.GetConfig().maxTemporalHistoryFrames))); app.set("previewFps", JsonValue(static_cast(runtimeStore.mConfigStore.GetConfig().previewFps))); app.set("enableExternalKeying", JsonValue(runtimeStore.mConfigStore.GetConfig().enableExternalKeying)); app.set("inputVideoFormat", JsonValue(runtimeStore.mConfigStore.GetConfig().inputVideoFormat)); app.set("inputFrameRate", JsonValue(runtimeStore.mConfigStore.GetConfig().inputFrameRate)); app.set("outputVideoFormat", JsonValue(runtimeStore.mConfigStore.GetConfig().outputVideoFormat)); app.set("outputFrameRate", JsonValue(runtimeStore.mConfigStore.GetConfig().outputFrameRate)); root.set("app", app); JsonValue runtime = JsonValue::MakeObject(); runtime.set("layerCount", JsonValue(static_cast(runtimeStore.mLayerStack.LayerCount()))); runtime.set("compileSucceeded", JsonValue(runtimeStore.mCompileSucceeded)); runtime.set("compileMessage", JsonValue(runtimeStore.mCompileMessage)); root.set("runtime", runtime); JsonValue video = JsonValue::MakeObject(); video.set("hasSignal", JsonValue(telemetrySnapshot.signal.hasSignal)); video.set("width", JsonValue(static_cast(telemetrySnapshot.signal.width))); video.set("height", JsonValue(static_cast(telemetrySnapshot.signal.height))); video.set("modeName", JsonValue(telemetrySnapshot.signal.modeName)); root.set("video", video); JsonValue deckLink = JsonValue::MakeObject(); deckLink.set("modelName", JsonValue(telemetrySnapshot.videoIO.modelName)); deckLink.set("supportsInternalKeying", JsonValue(telemetrySnapshot.videoIO.supportsInternalKeying)); deckLink.set("supportsExternalKeying", JsonValue(telemetrySnapshot.videoIO.supportsExternalKeying)); deckLink.set("keyerInterfaceAvailable", JsonValue(telemetrySnapshot.videoIO.keyerInterfaceAvailable)); deckLink.set("externalKeyingRequested", JsonValue(telemetrySnapshot.videoIO.externalKeyingRequested)); deckLink.set("externalKeyingActive", JsonValue(telemetrySnapshot.videoIO.externalKeyingActive)); deckLink.set("statusMessage", JsonValue(telemetrySnapshot.videoIO.statusMessage)); root.set("decklink", deckLink); JsonValue videoIO = JsonValue::MakeObject(); videoIO.set("backend", JsonValue(telemetrySnapshot.videoIO.backendName)); videoIO.set("modelName", JsonValue(telemetrySnapshot.videoIO.modelName)); videoIO.set("supportsInternalKeying", JsonValue(telemetrySnapshot.videoIO.supportsInternalKeying)); videoIO.set("supportsExternalKeying", JsonValue(telemetrySnapshot.videoIO.supportsExternalKeying)); videoIO.set("keyerInterfaceAvailable", JsonValue(telemetrySnapshot.videoIO.keyerInterfaceAvailable)); videoIO.set("externalKeyingRequested", JsonValue(telemetrySnapshot.videoIO.externalKeyingRequested)); videoIO.set("externalKeyingActive", JsonValue(telemetrySnapshot.videoIO.externalKeyingActive)); videoIO.set("statusMessage", JsonValue(telemetrySnapshot.videoIO.statusMessage)); root.set("videoIO", videoIO); JsonValue performance = JsonValue::MakeObject(); performance.set("frameBudgetMs", JsonValue(telemetrySnapshot.performance.frameBudgetMilliseconds)); performance.set("renderMs", JsonValue(telemetrySnapshot.performance.renderMilliseconds)); performance.set("smoothedRenderMs", JsonValue(telemetrySnapshot.performance.smoothedRenderMilliseconds)); performance.set("budgetUsedPercent", JsonValue( telemetrySnapshot.performance.frameBudgetMilliseconds > 0.0 ? (telemetrySnapshot.performance.smoothedRenderMilliseconds / telemetrySnapshot.performance.frameBudgetMilliseconds) * 100.0 : 0.0)); performance.set("completionIntervalMs", JsonValue(telemetrySnapshot.performance.completionIntervalMilliseconds)); performance.set("smoothedCompletionIntervalMs", JsonValue(telemetrySnapshot.performance.smoothedCompletionIntervalMilliseconds)); performance.set("maxCompletionIntervalMs", JsonValue(telemetrySnapshot.performance.maxCompletionIntervalMilliseconds)); performance.set("lateFrameCount", JsonValue(static_cast(telemetrySnapshot.performance.lateFrameCount))); performance.set("droppedFrameCount", JsonValue(static_cast(telemetrySnapshot.performance.droppedFrameCount))); performance.set("flushedFrameCount", JsonValue(static_cast(telemetrySnapshot.performance.flushedFrameCount))); root.set("performance", performance); JsonValue shaderLibrary = JsonValue::MakeArray(); for (const ShaderPackageStatus& status : runtimeStore.mShaderCatalog.PackageStatuses()) { JsonValue shader = JsonValue::MakeObject(); shader.set("id", JsonValue(status.id)); shader.set("name", JsonValue(status.displayName)); shader.set("description", JsonValue(status.description)); shader.set("category", JsonValue(status.category)); shader.set("available", JsonValue(status.available)); if (!status.available) shader.set("error", JsonValue(status.error)); const ShaderPackage* shaderPackage = runtimeStore.mShaderCatalog.FindPackage(status.id); if (status.available && shaderPackage && shaderPackage->temporal.enabled) { JsonValue temporal = JsonValue::MakeObject(); temporal.set("enabled", JsonValue(true)); temporal.set("historySource", JsonValue(RuntimeStateJson::TemporalHistorySourceToString(shaderPackage->temporal.historySource))); temporal.set("requestedHistoryLength", JsonValue(static_cast(shaderPackage->temporal.requestedHistoryLength))); temporal.set("effectiveHistoryLength", JsonValue(static_cast(shaderPackage->temporal.effectiveHistoryLength))); shader.set("temporal", temporal); } if (status.available && shaderPackage && shaderPackage->feedback.enabled) { JsonValue feedback = JsonValue::MakeObject(); feedback.set("enabled", JsonValue(true)); feedback.set("writePass", JsonValue(shaderPackage->feedback.writePassId)); shader.set("feedback", feedback); } shaderLibrary.pushBack(shader); } root.set("shaders", shaderLibrary); JsonValue stackPresets = JsonValue::MakeArray(); for (const std::string& presetName : runtimeStore.GetStackPresetNamesLocked()) stackPresets.pushBack(JsonValue(presetName)); root.set("stackPresets", stackPresets); root.set("layers", RuntimeStateJson::SerializeLayerStack(runtimeStore.mLayerStack, runtimeStore.mShaderCatalog)); return root; }