#include #include "RequestHandler.h" #include "../WebSocketServer.h" #include "../eventhandler/types/EventSubscription.h" #include "../obs-websocket.h" RequestResult RequestHandler::GetVersion(const Request& request) { json responseData; responseData["obsVersion"] = Utils::Obs::StringHelper::GetObsVersion(); responseData["obsWebSocketVersion"] = OBS_WEBSOCKET_VERSION; responseData["rpcVersion"] = OBS_WEBSOCKET_RPC_VERSION; responseData["availableRequests"] = GetRequestList(); QList imageWriterFormats = QImageWriter::supportedImageFormats(); std::vector supportedImageFormats; for (const QByteArray& format : imageWriterFormats) { supportedImageFormats.push_back(format.toStdString()); } responseData["supportedImageFormats"] = supportedImageFormats; return RequestResult::Success(responseData); } RequestResult RequestHandler::BroadcastCustomEvent(const Request& request) { RequestStatus::RequestStatus statusCode; std::string comment; if (!request.ValidateObject("eventData", statusCode, comment)) return RequestResult::Error(statusCode, comment); auto webSocketServer = GetWebSocketServer(); if (!webSocketServer) return RequestResult::Error(RequestStatus::RequestProcessingFailed, "Unable to send event."); webSocketServer->BroadcastEvent(EventSubscription::General, "CustomEvent", request.RequestData["eventData"]); return RequestResult::Success(); } RequestResult RequestHandler::GetStats(const Request& request) { json responseData = Utils::Obs::DataHelper::GetStats(); responseData["webSocketSessionIncomingMessages"] = _session->IncomingMessages(); responseData["webSocketSessionOutgoingMessages"] = _session->OutgoingMessages(); return RequestResult::Success(responseData); } RequestResult RequestHandler::GetHotkeyList(const Request& request) { json responseData; responseData["hotkeys"] = Utils::Obs::ListHelper::GetHotkeyNameList(); return RequestResult::Success(responseData); } RequestResult RequestHandler::TriggerHotkeyByName(const Request& request) { RequestStatus::RequestStatus statusCode; std::string comment; if (!request.ValidateString("hotkeyName", statusCode, comment)) return RequestResult::Error(statusCode, comment); obs_hotkey_t *hotkey = Utils::Obs::SearchHelper::GetHotkeyByName(request.RequestData["hotkeyName"]); if (!hotkey) return RequestResult::Error(RequestStatus::ResourceNotFound, "No hotkeys were found by that name."); obs_hotkey_trigger_routed_callback(obs_hotkey_get_id(hotkey), true); return RequestResult::Success(); } RequestResult RequestHandler::TriggerHotkeyByKeySequence(const Request& request) { obs_key_combination_t combo = {0}; RequestStatus::RequestStatus statusCode = RequestStatus::NoError; std::string comment; if (request.Contains("keyId")) { if (!request.ValidateOptionalString("keyId", statusCode, comment)) return RequestResult::Error(statusCode, comment); std::string keyId = request.RequestData["keyId"]; combo.key = obs_key_from_name(keyId.c_str()); } statusCode = RequestStatus::NoError; if (request.Contains("keyModifiers")) { if (!request.ValidateOptionalObject("keyModifiers", statusCode, comment, true)) return RequestResult::Error(statusCode, comment); const json keyModifiersJson = request.RequestData["keyModifiers"]; uint32_t keyModifiers = 0; if (keyModifiersJson.contains("shift") && keyModifiersJson["shift"].is_boolean() && keyModifiersJson["shift"].get()) keyModifiers |= INTERACT_SHIFT_KEY; if (keyModifiersJson.contains("control") && keyModifiersJson["control"].is_boolean() && keyModifiersJson["control"].get()) keyModifiers |= INTERACT_CONTROL_KEY; if (keyModifiersJson.contains("alt") && keyModifiersJson["alt"].is_boolean() && keyModifiersJson["alt"].get()) keyModifiers |= INTERACT_ALT_KEY; if (keyModifiersJson.contains("command") && keyModifiersJson["command"].is_boolean() && keyModifiersJson["command"].get()) keyModifiers |= INTERACT_COMMAND_KEY; combo.modifiers = keyModifiers; } if (!combo.modifiers && (combo.key == OBS_KEY_NONE || combo.key >= OBS_KEY_LAST_VALUE)) return RequestResult::Error(RequestStatus::CannotAct, "Your provided request parameters cannot be used to trigger a hotkey."); // Apparently things break when you don't start by setting the combo to false obs_hotkey_inject_event(combo, false); obs_hotkey_inject_event(combo, true); obs_hotkey_inject_event(combo, false); return RequestResult::Success(); } RequestResult RequestHandler::GetStudioModeEnabled(const Request& request) { json responseData; responseData["studioModeEnabled"] = obs_frontend_preview_program_mode_active(); return RequestResult::Success(responseData); } RequestResult RequestHandler::SetStudioModeEnabled(const Request& request) { RequestStatus::RequestStatus statusCode; std::string comment; if (!request.ValidateBoolean("studioModeEnabled", statusCode, comment)) return RequestResult::Error(statusCode, comment); // Avoid queueing tasks if nothing will change if (obs_frontend_preview_program_mode_active() != request.RequestData["studioModeEnabled"]) { // (Bad) Create a boolean then pass it as a reference to the task. Requires `wait` in obs_queue_task() to be true, else undefined behavior bool studioModeEnabled = request.RequestData["studioModeEnabled"]; // Queue the task inside of the UI thread to prevent race conditions obs_queue_task(OBS_TASK_UI, [](void* param) { auto studioModeEnabled = (bool*)param; obs_frontend_set_preview_program_mode(*studioModeEnabled); }, &studioModeEnabled, true); } return RequestResult::Success(); } RequestResult RequestHandler::Sleep(const Request& request) { RequestStatus::RequestStatus statusCode; std::string comment; if (request.RequestBatchExecutionType == OBS_WEBSOCKET_REQUEST_BATCH_EXECUTION_TYPE_SERIAL_REALTIME) { if (!request.ValidateNumber("sleepMillis", statusCode, comment, 0, 50000)) return RequestResult::Error(statusCode, comment); int64_t sleepMillis = request.RequestData["sleepMillis"]; std::this_thread::sleep_for(std::chrono::milliseconds(sleepMillis)); return RequestResult::Success(); } else if (request.RequestBatchExecutionType == OBS_WEBSOCKET_REQUEST_BATCH_EXECUTION_TYPE_SERIAL_FRAME) { if (!request.ValidateNumber("sleepFrames", statusCode, comment, 0, 10000)) return RequestResult::Error(statusCode, comment); RequestResult ret = RequestResult::Success(); ret.SleepFrames = request.RequestData["sleepFrames"]; return ret; } else { return RequestResult::Error(RequestStatus::UnsupportedRequestBatchExecutionType); } }