Files
obs-websocket/src/requesthandler/RequestHandler_Transitions.cpp
tt2468 7adfb5874c requesthandler: Implement input, scene, and transition UUID support
Transition UUID support is partial due to the current state of the OBS
frontend API.

Most requests which accepted things like `sourceName` now allow
`sourceUuid` (or equivalent) to be specified instead. While both fields
on the various requests may be marked as optional, at least one field
will still be required.
2024-01-18 19:27:57 -08:00

334 lines
11 KiB
C++

/*
obs-websocket
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/
#include <math.h>
#include "RequestHandler.h"
/**
* Gets an array of all available transition kinds.
*
* Similar to `GetInputKindList`
*
* @responseField transitionKinds | Array<String> | Array of transition kinds
*
* @requestType GetTransitionKindList
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category transitions
*/
RequestResult RequestHandler::GetTransitionKindList(const Request &)
{
json responseData;
responseData["transitionKinds"] = Utils::Obs::ArrayHelper::GetTransitionKindList();
return RequestResult::Success(responseData);
}
/**
* Gets an array of all scene transitions in OBS.
*
* @responseField currentSceneTransitionName | String | Name of the current scene transition. Can be null
* @responseField currentSceneTransitionUuid | String | UUID of the current scene transition. Can be null
* @responseField currentSceneTransitionKind | String | Kind of the current scene transition. Can be null
* @responseField transitions | Array<Object> | Array of transitions
*
* @requestType GetSceneTransitionList
* @complexity 3
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category transitions
*/
RequestResult RequestHandler::GetSceneTransitionList(const Request &)
{
json responseData;
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
if (transition) {
responseData["currentSceneTransitionName"] = obs_source_get_name(transition);
responseData["currentSceneTransitionUuid"] = obs_source_get_uuid(transition);
responseData["currentSceneTransitionKind"] = obs_source_get_id(transition);
} else {
responseData["currentSceneTransitionName"] = nullptr;
responseData["currentSceneTransitionUuid"] = nullptr;
responseData["currentSceneTransitionKind"] = nullptr;
}
responseData["transitions"] = Utils::Obs::ArrayHelper::GetSceneTransitionList();
return RequestResult::Success(responseData);
}
/**
* Gets information about the current scene transition.
*
* @responseField transitionName | String | Name of the transition
* @responseField transitionUuid | String | UUID of the transition
* @responseField transitionKind | String | Kind of the transition
* @responseField transitionFixed | Boolean | Whether the transition uses a fixed (unconfigurable) duration
* @responseField transitionDuration | Number | Configured transition duration in milliseconds. `null` if transition is fixed
* @responseField transitionConfigurable | Boolean | Whether the transition supports being configured
* @responseField transitionSettings | Object | Object of settings for the transition. `null` if transition is not configurable
*
* @requestType GetCurrentSceneTransition
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category transitions
*/
RequestResult RequestHandler::GetCurrentSceneTransition(const Request &)
{
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
if (!transition)
return RequestResult::Error(RequestStatus::InvalidResourceState,
"OBS does not currently have a scene transition set."); // This should not happen!
json responseData;
responseData["transitionName"] = obs_source_get_name(transition);
responseData["transitionUuid"] = obs_source_get_uuid(transition);
responseData["transitionKind"] = obs_source_get_id(transition);
if (obs_transition_fixed(transition)) {
responseData["transitionFixed"] = true;
responseData["transitionDuration"] = nullptr;
} else {
responseData["transitionFixed"] = false;
responseData["transitionDuration"] = obs_frontend_get_transition_duration();
}
if (obs_source_configurable(transition)) {
responseData["transitionConfigurable"] = true;
OBSDataAutoRelease transitionSettings = obs_source_get_settings(transition);
responseData["transitionSettings"] = Utils::Json::ObsDataToJson(transitionSettings);
} else {
responseData["transitionConfigurable"] = false;
responseData["transitionSettings"] = nullptr;
}
return RequestResult::Success(responseData);
}
/**
* Sets the current scene transition.
*
* Small note: While the namespace of scene transitions is generally unique, that uniqueness is not a guarantee as it is with other resources like inputs.
*
* @requestField transitionName | String | Name of the transition to make active
*
* @requestType SetCurrentSceneTransition
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category transitions
*/
RequestResult RequestHandler::SetCurrentSceneTransition(const Request &request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
if (!request.ValidateString("transitionName", statusCode, comment))
return RequestResult::Error(statusCode, comment);
std::string transitionName = request.RequestData["transitionName"];
OBSSourceAutoRelease transition = Utils::Obs::SearchHelper::GetSceneTransitionByName(transitionName);
if (!transition)
return RequestResult::Error(RequestStatus::ResourceNotFound, "No scene transition was found by that name.");
obs_frontend_set_current_transition(transition);
return RequestResult::Success();
}
/**
* Sets the duration of the current scene transition, if it is not fixed.
*
* @requestField transitionDuration | Number | Duration in milliseconds | >= 50, <= 20000
*
* @requestType SetCurrentSceneTransitionDuration
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category transitions
*/
RequestResult RequestHandler::SetCurrentSceneTransitionDuration(const Request &request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
if (!request.ValidateNumber("transitionDuration", statusCode, comment, 50, 20000))
return RequestResult::Error(statusCode, comment);
int transitionDuration = request.RequestData["transitionDuration"];
obs_frontend_set_transition_duration(transitionDuration);
return RequestResult::Success();
}
/**
* Sets the settings of the current scene transition.
*
* @requestField transitionSettings | Object | Settings object to apply to the transition. Can be `{}`
* @requestField ?overlay | Boolean | Whether to overlay over the current settings or replace them | true
*
* @requestType SetCurrentSceneTransitionSettings
* @complexity 3
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category transitions
*/
RequestResult RequestHandler::SetCurrentSceneTransitionSettings(const Request &request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
if (!request.ValidateObject("transitionSettings", statusCode, comment, true))
return RequestResult::Error(statusCode, comment);
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
if (!transition)
return RequestResult::Error(RequestStatus::InvalidResourceState,
"OBS does not currently have a scene transition set."); // This should not happen!
if (!obs_source_configurable(transition))
return RequestResult::Error(RequestStatus::ResourceNotConfigurable,
"The current transition does not support custom settings.");
bool overlay = true;
if (request.Contains("overlay")) {
if (!request.ValidateOptionalBoolean("overlay", statusCode, comment))
return RequestResult::Error(statusCode, comment);
overlay = request.RequestData["overlay"];
}
OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["transitionSettings"]);
if (!newSettings)
return RequestResult::Error(RequestStatus::RequestProcessingFailed,
"An internal data conversion operation failed. Please report this!");
if (overlay)
obs_source_update(transition, newSettings);
else
obs_source_reset_settings(transition, newSettings);
obs_source_update_properties(transition);
return RequestResult::Success();
}
/**
* Gets the cursor position of the current scene transition.
*
* Note: `transitionCursor` will return 1.0 when the transition is inactive.
*
* @responseField transitionCursor | Number | Cursor position, between 0.0 and 1.0
*
* @requestType GetCurrentSceneTransitionCursor
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category transitions
*/
RequestResult RequestHandler::GetCurrentSceneTransitionCursor(const Request &)
{
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
if (!transition)
return RequestResult::Error(RequestStatus::InvalidResourceState,
"OBS does not currently have a scene transition set."); // This should not happen!
json responseData;
responseData["transitionCursor"] = obs_transition_get_time(transition);
return RequestResult::Success(responseData);
}
/**
* Triggers the current scene transition. Same functionality as the `Transition` button in studio mode.
*
* @requestType TriggerStudioModeTransition
* @complexity 1
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category transitions
*/
RequestResult RequestHandler::TriggerStudioModeTransition(const Request &)
{
if (!obs_frontend_preview_program_mode_active())
return RequestResult::Error(RequestStatus::StudioModeNotActive);
OBSSourceAutoRelease previewScene = obs_frontend_get_current_preview_scene();
obs_frontend_set_current_scene(previewScene);
return RequestResult::Success();
}
/**
* Sets the position of the TBar.
*
* **Very important note**: This will be deprecated and replaced in a future version of obs-websocket.
*
* @requestField position | Number | New position | >= 0.0, <= 1.0
* @requestField ?release | Boolean | Whether to release the TBar. Only set `false` if you know that you will be sending another position update | `true`
*
* @requestType SetTBarPosition
* @complexity 3
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category transitions
*/
RequestResult RequestHandler::SetTBarPosition(const Request &request)
{
if (!obs_frontend_preview_program_mode_active())
return RequestResult::Error(RequestStatus::StudioModeNotActive);
RequestStatus::RequestStatus statusCode;
std::string comment;
if (!request.ValidateNumber("position", statusCode, comment, 0.0, 1.0))
return RequestResult::Error(statusCode, comment);
bool release = true;
if (request.Contains("release")) {
if (!request.ValidateOptionalBoolean("release", statusCode, comment))
return RequestResult::Error(statusCode, comment);
}
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
if (!transition)
return RequestResult::Error(RequestStatus::InvalidResourceState,
"OBS does not currently have a scene transition set."); // This should not happen!
float position = request.RequestData["position"];
obs_frontend_set_tbar_position((int)round(position * 1024.0));
if (release)
obs_frontend_release_tbar();
return RequestResult::Success();
}