diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index e3ba574a..b93cf69e 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -105,6 +105,9 @@ const std::unordered_map RequestHandler::_han {"SetCurrentSceneTransitionSettings", &RequestHandler::SetCurrentSceneTransitionSettings}, {"TriggerStudioModeTransition", &RequestHandler::TriggerStudioModeTransition}, + // Filters + {"GetSourceFilter", &RequestHandler::GetSourceFilter}, + // Scene Items {"GetSceneItemList", &RequestHandler::GetSceneItemList}, {"GetGroupSceneItemList", &RequestHandler::GetGroupSceneItemList}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 40967ca0..7e920d19 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -123,6 +123,9 @@ class RequestHandler { RequestResult SetCurrentSceneTransitionSettings(const Request&); RequestResult TriggerStudioModeTransition(const Request&); + // Filters + RequestResult GetSourceFilter(const Request&); + // Scene Items RequestResult GetSceneItemList(const Request&); RequestResult GetGroupSceneItemList(const Request&); diff --git a/src/requesthandler/RequestHandler_Filters.cpp b/src/requesthandler/RequestHandler_Filters.cpp index b09e414c..7bb6e0e0 100644 --- a/src/requesthandler/RequestHandler_Filters.cpp +++ b/src/requesthandler/RequestHandler_Filters.cpp @@ -18,3 +18,40 @@ with this program. If not, see */ #include "RequestHandler.h" + +/** + * Gets the info for a specific source filter. + * + * @requestField sourceName | String | Name of the source + * @requestField filterName | String | Name of the filter + * + * @responseField filterEnabled | Boolean | Whether the filter is enabled + * @responseField filterIndex | Number | Index of the filter in the list, beginning at 0 + * @responseField filterKind | String | The kind of filter + * @responseField filterSettings | Object | Settings object associated with the filter + * + * @requestType GetSourceFilter + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category filters + */ +RequestResult RequestHandler::GetSourceFilter(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); + if (!pair.filter) + return RequestResult::Error(statusCode, comment); + + json responseData; + responseData["filterEnabled"] = obs_source_enabled(pair.filter); + responseData["filterIndex"] = Utils::Obs::NumberHelper::GetSourceFilterIndex(pair.source, pair.filter); // Todo: Use `GetSourceFilterlist` to select this filter maybe + responseData["filterKind"] = obs_source_get_id(pair.filter); + + OBSDataAutoRelease filterSettings = obs_source_get_settings(pair.filter); + responseData["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings); + + return RequestResult::Success(responseData); +} diff --git a/src/requesthandler/rpc/Request.cpp b/src/requesthandler/rpc/Request.cpp index 418268e3..cd55abeb 100644 --- a/src/requesthandler/rpc/Request.cpp +++ b/src/requesthandler/rpc/Request.cpp @@ -295,6 +295,27 @@ obs_source_t *Request::ValidateInput(const std::string &keyName, RequestStatus:: return ret; } +FilterPair Request::ValidateFilter(const std::string &sourceKeyName, const std::string &filterKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const +{ + obs_source_t *source = ValidateSource(sourceKeyName, statusCode, comment); + if (!source) + return FilterPair{source, nullptr}; + + if (!ValidateString(filterKeyName, statusCode, comment)) + return FilterPair{source, nullptr}; + + std::string filterName = RequestData[filterKeyName]; + + obs_source_t *filter = obs_source_get_filter_by_name(source, filterName.c_str()); + if (!filter) { + statusCode = RequestStatus::ResourceNotFound; + comment = std::string("No filter was found in the source `") + RequestData[sourceKeyName].get() + "` with the name `" + filterName + "`."; + return FilterPair{source, nullptr}; + } + + return FilterPair{source, filter}; +} + obs_sceneitem_t *Request::ValidateSceneItem(const std::string &sceneKeyName, const std::string &sceneItemIdKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter) const { OBSSceneAutoRelease scene = ValidateScene2(sceneKeyName, statusCode, comment, filter); diff --git a/src/requesthandler/rpc/Request.h b/src/requesthandler/rpc/Request.h index 03f6fb21..0f44308b 100644 --- a/src/requesthandler/rpc/Request.h +++ b/src/requesthandler/rpc/Request.h @@ -29,6 +29,12 @@ enum ObsWebSocketSceneFilter { OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP, }; +// We return filters as a pair because `obs_filter_get_parent()` is apparently volatile +struct FilterPair { + OBSSourceAutoRelease source; + OBSSourceAutoRelease filter; +}; + struct Request { Request(const std::string &requestType, const json &requestData = nullptr, const RequestBatchExecutionType::RequestBatchExecutionType executionType = RequestBatchExecutionType::None); @@ -53,6 +59,7 @@ struct Request obs_source_t *ValidateScene(const std::string &keyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const; obs_scene_t *ValidateScene2(const std::string &keyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const; obs_source_t *ValidateInput(const std::string &keyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const; + FilterPair ValidateFilter(const std::string &sourceKeyName, const std::string &filterKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const; obs_sceneitem_t *ValidateSceneItem(const std::string &sceneKeyName, const std::string &sceneItemIdKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const; std::string RequestType; diff --git a/src/utils/Obs.h b/src/utils/Obs.h index fb5e0899..f0d1baff 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -177,6 +177,7 @@ namespace Utils { namespace NumberHelper { uint64_t GetOutputDuration(obs_output_t *output); size_t GetSceneCount(); + size_t GetSourceFilterIndex(obs_source_t *source, obs_source_t *filter); } namespace ArrayHelper { diff --git a/src/utils/Obs_NumberHelper.cpp b/src/utils/Obs_NumberHelper.cpp index e7c22c9b..a510c783 100644 --- a/src/utils/Obs_NumberHelper.cpp +++ b/src/utils/Obs_NumberHelper.cpp @@ -52,3 +52,28 @@ size_t Utils::Obs::NumberHelper::GetSceneCount() return ret; } + +size_t Utils::Obs::NumberHelper::GetSourceFilterIndex(obs_source_t *source, obs_source_t *filter) +{ + struct FilterSearch { + obs_source_t *filter; + bool found; + size_t index; + }; + + auto search = [](obs_source_t *, obs_source_t *filter, void *priv_data) { + auto filterSearch = static_cast(priv_data); + + if (filter == filterSearch->filter) + filterSearch->found = true; + + if (!filterSearch->found) + filterSearch->index++; + }; + + FilterSearch filterSearch = {filter, 0, 0}; + + obs_source_enum_filters(source, search, &filterSearch); + + return filterSearch.index; +}