obs-websocket/src/requesthandler/RequestHandler_Inputs.cpp

408 lines
15 KiB
C++

#include "RequestHandler.h"
RequestResult RequestHandler::GetInputList(const Request& request)
{
std::string inputKind;
if (request.RequestData.contains("inputKind") && !request.RequestData["inputKind"].is_null()) {
RequestStatus::RequestStatus statusCode;
std::string comment;
if (!request.ValidateString("inputKind", statusCode, comment))
return RequestResult::Error(statusCode, comment);
inputKind = request.RequestData["inputKind"];
}
json responseData;
responseData["inputs"] = Utils::Obs::ListHelper::GetInputList(inputKind);
return RequestResult::Success(responseData);
}
RequestResult RequestHandler::GetInputKindList(const Request& request)
{
bool unversioned = false;
if (request.RequestData.contains("unversioned") && !request.RequestData["unversioned"].is_null()) {
RequestStatus::RequestStatus statusCode;
std::string comment;
if (!request.ValidateBoolean("unversioned", statusCode, comment))
return RequestResult::Error(statusCode, comment);
unversioned = request.RequestData["unversioned"];
}
json responseData;
responseData["inputKinds"] = Utils::Obs::ListHelper::GetInputKindList(unversioned);
return RequestResult::Success(responseData);
}
RequestResult RequestHandler::CreateInput(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease sceneSource = request.ValidateScene("sceneName", statusCode, comment);
if (!(request.ValidateString("inputName", statusCode, comment) &&
request.ValidateString("inputKind", statusCode, comment) &&
sceneSource))
return RequestResult::Error(statusCode, comment);
std::string inputName = request.RequestData["inputName"];
OBSSourceAutoRelease existingInput = obs_get_source_by_name(inputName.c_str());
if (existingInput)
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A source already exists by that input name.");
std::string inputKind = request.RequestData["inputKind"];
auto kinds = Utils::Obs::ListHelper::GetInputKindList();
if (std::find(kinds.begin(), kinds.end(), inputKind) == kinds.end())
return RequestResult::Error(RequestStatus::InvalidInputKind, "Your specified input kind is not supported by OBS. Check that your specified kind is properly versioned and that any necessary plugins are loaded.");
OBSDataAutoRelease inputSettings = nullptr;
if (request.RequestData.contains("inputSettings") && !request.RequestData["inputSettings"].is_null()) {
if (!request.ValidateObject("inputSettings", statusCode, comment, true))
return RequestResult::Error(statusCode, comment);
inputSettings = Utils::Json::JsonToObsData(request.RequestData["inputSettings"]);
}
OBSScene scene = obs_scene_from_source(sceneSource);
bool sceneItemEnabled = true;
if (request.RequestData.contains("sceneItemEnabled") && !request.RequestData["sceneItemEnabled"].is_null()) {
if (!request.ValidateBoolean("sceneItemEnabled", statusCode, comment))
return RequestResult::Error(statusCode, comment);
sceneItemEnabled = request.RequestData["sceneItemEnabled"];
}
// Create the input and add it as a scene item to the destination scene
obs_sceneitem_t *sceneItem = Utils::Obs::ActionHelper::CreateInput(inputName, inputKind, inputSettings, scene, sceneItemEnabled);
if (!sceneItem)
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "Creation of the input or scene item failed.");
json responseData;
responseData["sceneItemId"] = obs_sceneitem_get_id(sceneItem);
return RequestResult::Success(responseData);
}
RequestResult RequestHandler::SetInputName(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!(input && request.ValidateString("newInputName", statusCode, comment)))
return RequestResult::Error(statusCode, comment);
std::string newInputName = request.RequestData["newInputName"];
OBSSourceAutoRelease existingSource = obs_get_source_by_name(newInputName.c_str());
if (existingSource)
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A source already exists by that new input name.");
obs_source_set_name(input, newInputName.c_str());
return RequestResult::Success();
}
RequestResult RequestHandler::GetInputDefaultSettings(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
if (!request.ValidateString("inputKind", statusCode, comment))
return RequestResult::Error(statusCode, comment);
std::string inputKind = request.RequestData["inputKind"];
OBSDataAutoRelease defaultSettings = obs_get_source_defaults(inputKind.c_str());
if (!defaultSettings)
return RequestResult::Error(RequestStatus::InvalidInputKind);
json responseData;
responseData["defaultInputSettings"] = Utils::Json::ObsDataToJson(defaultSettings, true);
return RequestResult::Success(responseData);
}
RequestResult RequestHandler::GetInputSettings(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!input)
return RequestResult::Error(statusCode, comment);
OBSDataAutoRelease inputSettings = obs_source_get_settings(input);
json responseData;
responseData["inputSettings"] = Utils::Json::ObsDataToJson(inputSettings);
responseData["inputKind"] = obs_source_get_id(input);
return RequestResult::Success(responseData);
}
RequestResult RequestHandler::SetInputSettings(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!(input && request.ValidateObject("inputSettings", statusCode, comment, true)))
return RequestResult::Error(statusCode, comment);
bool overlay = true;
if (request.RequestData.contains("overlay") && !request.RequestData["overlay"].is_null()) {
if (!request.ValidateBoolean("overlay", statusCode, comment))
return RequestResult::Error(statusCode, comment);
overlay = request.RequestData["overlay"];
}
// Get the new settings and convert it to obs_data_t*
OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["inputSettings"]);
if (!newSettings)
// This should never happen
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "An internal data conversion operation failed. Please report this!");
if (overlay)
// Applies the new settings on top of the existing user settings
obs_source_update(input, newSettings);
else
// Clears all user settings (leaving defaults) then applies the new settings
obs_source_reset_settings(input, newSettings);
// Tells any open source properties windows to perform a UI refresh
obs_source_update_properties(input);
return RequestResult::Success();
}
RequestResult RequestHandler::GetInputMute(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!input)
return RequestResult::Error(statusCode, comment);
json responseData;
responseData["inputMuted"] = obs_source_muted(input);
return RequestResult::Success(responseData);
}
RequestResult RequestHandler::SetInputMute(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!(input && request.ValidateBoolean("inputMuted", statusCode, comment)))
return RequestResult::Error(statusCode, comment);
obs_source_set_muted(input, request.RequestData["inputMuted"]);
return RequestResult::Success();
}
RequestResult RequestHandler::ToggleInputMute(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!input)
return RequestResult::Error(statusCode, comment);
bool inputMuted = !obs_source_muted(input);
obs_source_set_muted(input, inputMuted);
json responseData;
responseData["inputMuted"] = inputMuted;
return RequestResult::Success(responseData);
}
RequestResult RequestHandler::GetInputVolume(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!input)
return RequestResult::Error(statusCode, comment);
float inputVolumeMul = obs_source_get_volume(input);
float inputVolumeDb = obs_mul_to_db(inputVolumeMul);
if (inputVolumeDb == -INFINITY)
inputVolumeDb = -100.0;
json responseData;
responseData["inputVolumeMul"] = inputVolumeMul;
responseData["inputVolumeDb"] = inputVolumeDb;
return RequestResult::Success(responseData);
}
RequestResult RequestHandler::SetInputVolume(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!input)
return RequestResult::Error(statusCode, comment);
bool hasMul = request.ValidateNumber("inputVolumeMul", statusCode, comment, 0, 20);
if (!hasMul && statusCode != RequestStatus::MissingRequestParameter)
return RequestResult::Error(statusCode, comment);
bool hasDb = request.ValidateNumber("inputVolumeDb", statusCode, comment, -100, 26);
if (!hasDb && statusCode != RequestStatus::MissingRequestParameter)
return RequestResult::Error(statusCode, comment);
if (hasMul && hasDb)
return RequestResult::Error(RequestStatus::TooManyRequestParameters, "You may only specify one volume parameter.");
if (!hasMul && !hasDb)
return RequestResult::Error(RequestStatus::MissingRequestParameter, "You must specify one volume parameter.");
float inputVolumeMul = 0.0;
if (hasMul)
inputVolumeMul = request.RequestData["inputVolumeMul"];
else
inputVolumeMul = obs_db_to_mul(request.RequestData["inputVolumeDb"]);
obs_source_set_volume(input, inputVolumeMul);
return RequestResult::Success();
}
RequestResult RequestHandler::GetInputAudioSyncOffset(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!input)
return RequestResult::Error(statusCode, comment);
json responseData;
// Offset is stored in nanoseconds in OBS.
responseData["inputAudioSyncOffset"] = obs_source_get_sync_offset(input) / 1000000;
return RequestResult::Success(responseData);
}
RequestResult RequestHandler::SetInputAudioSyncOffset(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!(input && request.ValidateNumber("inputAudioSyncOffset", statusCode, comment, -950, 20000)))
return RequestResult::Error(statusCode, comment);
int64_t syncOffset = request.RequestData["inputAudioSyncOffset"];
obs_source_set_sync_offset(input, syncOffset * 1000000);
return RequestResult::Success();
}
RequestResult RequestHandler::GetInputAudioMonitorType(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!input)
return RequestResult::Error(statusCode, comment);
json responseData;
responseData["monitorType"] = Utils::Obs::StringHelper::GetInputMonitorTypeString(input);
return RequestResult::Success(responseData);
}
RequestResult RequestHandler::SetInputAudioMonitorType(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!(input && request.ValidateString("monitorType", statusCode, comment)))
return RequestResult::Error(statusCode, comment);
enum obs_monitoring_type monitorType;
std::string monitorTypeString = request.RequestData["monitorType"];
if (monitorTypeString == "OBS_MONITORING_TYPE_NONE")
monitorType = OBS_MONITORING_TYPE_NONE;
else if (monitorTypeString == "OBS_MONITORING_TYPE_MONITOR_ONLY")
monitorType = OBS_MONITORING_TYPE_MONITOR_ONLY;
else if (monitorTypeString == "OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT")
monitorType = OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT;
else
return RequestResult::Error(RequestStatus::InvalidRequestParameter, std::string("Unknown monitor type: ") + monitorTypeString);
obs_source_set_monitoring_type(input, monitorType);
return RequestResult::Success();
}
std::vector<json> GetListPropertyItems(obs_property_t *property)
{
std::vector<json> ret;
enum obs_combo_format itemFormat = obs_property_list_format(property);
size_t itemCount = obs_property_list_item_count(property);
for (size_t i = 0; i < itemCount; i++) {
json itemData;
itemData["itemName"] = obs_property_list_item_name(property, i);
itemData["itemEnabled"] = !obs_property_list_item_disabled(property, i);
if (itemFormat == OBS_COMBO_FORMAT_INT) {
itemData["itemValue"] = obs_property_list_item_int(property, i);
} else if (itemFormat == OBS_COMBO_FORMAT_FLOAT) {
itemData["itemValue"] = obs_property_list_item_float(property, i);
} else if (itemFormat == OBS_COMBO_FORMAT_STRING) {
itemData["itemValue"] = obs_property_list_item_string(property, i);
}
ret.push_back(itemData);
}
return ret;
}
RequestResult RequestHandler::GetInputPropertiesListPropertyItems(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!(input && request.ValidateString("propertyName", statusCode, comment)))
return RequestResult::Error(statusCode, comment);
std::string propertyName = request.RequestData["propertyName"];
OBSPropertiesAutoDestroy inputProperties = obs_source_properties(input);
obs_property_t *property = obs_properties_get(inputProperties, propertyName.c_str());
if (!property)
return RequestResult::Error(RequestStatus::ResourceNotFound, "Unable to find a property by that name.");
if (obs_property_get_type(property) != OBS_PROPERTY_LIST)
return RequestResult::Error(RequestStatus::InvalidResourceType, "The property found is not a list.");
json responseData;
responseData["propertyItems"] = GetListPropertyItems(property);
return RequestResult::Success(responseData);
}
RequestResult RequestHandler::PressInputPropertiesButton(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
if (!(input && request.ValidateString("propertyName", statusCode, comment)))
return RequestResult::Error(statusCode, comment);
std::string propertyName = request.RequestData["propertyName"];
OBSPropertiesAutoDestroy inputProperties = obs_source_properties(input);
obs_property_t *property = obs_properties_get(inputProperties, propertyName.c_str());
if (!property)
return RequestResult::Error(RequestStatus::ResourceNotFound, "Unable to find a property by that name.");
if (obs_property_get_type(property) != OBS_PROPERTY_BUTTON)
return RequestResult::Error(RequestStatus::InvalidResourceType, "The property found is not a button.");
if (!obs_property_enabled(property))
return RequestResult::Error(RequestStatus::InvalidResourceState, "The property item found is not enabled.");
obs_property_button_clicked(property, input);
return RequestResult::Success();
}