requesthandler: Filter requests & events (#888)

* Implement filter requests

* Fix CreateSourceFilter

* Implement most Filter events

* build against 27.1.3

* Update main.yml

* SourceFilterNameChanged rename

* revert main.yml changes

* rename SourceFilterCreated and revert CI changes

* cleanup

* Base: Various cleanups + fix -Werror

* Base: A few nitpicks/fixes

* requesthandler: Fix CreateSourceFilter

* utils: Fix CreateSourceFilter

Use obs_source_t* instead of OBSSourceAutoRelease to prevent double
release

* requesthandler: Remove filterIndex from CreateSourceFilter

The purpose of sceneItemEnabled in CreateSceneItem is to hide the
scene item while we still hold the scene mutex (guaranteeing the input
will never be shown). Since we don't hold a mutex when creating
filters, there's no reason to do any extra steps.

* requesthandler: Validate input/filter kinds in *DefaultSettings

Co-authored-by: tt2468 <tt2468@gmail.com>
This commit is contained in:
Brendan Allan 2022-02-17 05:17:06 +08:00 committed by GitHub
parent b3a5c55bef
commit 361547a96d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 613 additions and 25 deletions

1
.gitignore vendored
View File

@ -11,3 +11,4 @@
/docs/node_modules/
/src/plugin-macros.generated.h
/installer/installer-windows.generated.iss
/cmake-build-debug/

View File

@ -135,9 +135,12 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inpu
signal_handler_connect(sh, "mute", HandleInputMuteStateChanged, this);
signal_handler_connect(sh, "volume", HandleInputVolumeChanged, this);
signal_handler_connect(sh, "audio_balance", HandleInputAudioBalanceChanged, this);
signal_handler_connect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this);
signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this);
signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this);
signal_handler_connect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this);
signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this);
signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this);
signal_handler_connect(sh, "filter_add", HandleSourceFilterCreated, this);
signal_handler_connect(sh, "filter_remove", HandleSourceFilterRemoved, this);
signal_handler_connect(sh, "reorder_filters", HandleSourceFilterListReindexed, this);
if (sourceType == OBS_SOURCE_TYPE_INPUT) {
signal_handler_connect(sh, "media_started", HandleMediaInputPlaybackStarted, this);
@ -188,6 +191,9 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source)
signal_handler_disconnect(sh, "media_stopped", SourceMediaStopMultiHandler, this);
signal_handler_disconnect(sh, "media_next", SourceMediaNextMultiHandler, this);
signal_handler_disconnect(sh, "media_previous", SourceMediaPreviousMultiHandler, this);
signal_handler_disconnect(sh, "filter_add", HandleSourceFilterCreated, this);
signal_handler_disconnect(sh, "filter_remove", HandleSourceFilterRemoved, this);
signal_handler_disconnect(sh, "reorder_filters", HandleSourceFilterListReindexed, this);
// Scenes
signal_handler_disconnect(sh, "item_add", HandleSceneItemCreated, this);
@ -199,6 +205,30 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source)
signal_handler_disconnect(sh, "item_transform", HandleSceneItemTransformChanged, this);
}
void EventHandler::ConnectFilterSignals(obs_source_t *filter)
{
if (!filter || obs_source_removed(filter))
return;
DisconnectFilterSignals(filter);
signal_handler_t* sh = obs_source_get_signal_handler(filter);
signal_handler_connect(sh, "enable", HandleSourceFilterEnableStateChanged, this);
signal_handler_connect(sh, "rename", HandleSourceFilterNameChanged, this);
}
void EventHandler::DisconnectFilterSignals(obs_source_t *filter)
{
if (!filter)
return;
signal_handler_t* sh = obs_source_get_signal_handler(filter);
signal_handler_disconnect(sh, "enable", HandleSourceFilterEnableStateChanged, this);
signal_handler_disconnect(sh, "rename", HandleSourceFilterNameChanged, this);
}
void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_data)
{
auto eventHandler = static_cast<EventHandler*>(private_data);
@ -211,18 +241,38 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
// In the case that plugins become hotloadable, this will have to go back into `EventHandler::EventHandler()`
// Enumerate inputs and connect each one
obs_enum_sources([](void* param, obs_source_t* source) {
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->ConnectSourceSignals(source);
return true;
}, private_data);
{
auto enumInputs = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->ConnectSourceSignals(source);
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->ConnectFilterSignals(filter);
};
obs_source_enum_filters(source, enumFilters, param);
return true;
};
obs_enum_sources(enumInputs, private_data);
}
// Enumerate scenes and connect each one
obs_enum_scenes([](void* param, obs_source_t* source) {
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->ConnectSourceSignals(source);
return true;
}, private_data);
{
auto enumScenes = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->ConnectSourceSignals(source);
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->ConnectFilterSignals(filter);
};
obs_source_enum_filters(source, enumFilters, param);
return true;
};
obs_enum_scenes(enumScenes, private_data);
}
blog_debug("[EventHandler::OnFrontendEvent] Finished.");
@ -244,18 +294,38 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
// In the case that plugins become hotloadable, this will have to go back into `EventHandler::~EventHandler()`
// Enumerate inputs and disconnect each one
obs_enum_sources([](void* param, obs_source_t* source) {
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->DisconnectSourceSignals(source);
return true;
}, private_data);
{
auto enumInputs = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->DisconnectSourceSignals(source);
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->ConnectFilterSignals(filter);
};
obs_source_enum_filters(source, enumFilters, param);
return true;
};
obs_enum_sources(enumInputs, private_data);
}
// Enumerate scenes and disconnect each one
obs_enum_scenes([](void* param, obs_source_t* source) {
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->DisconnectSourceSignals(source);
return true;
}, private_data);
{
auto enumScenes = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->DisconnectSourceSignals(source);
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){
auto eventHandler = static_cast<EventHandler*>(param);
eventHandler->ConnectFilterSignals(filter);
};
obs_source_enum_filters(source, enumFilters, param);
return true;
};
obs_enum_scenes(enumScenes, private_data);
}
blog_debug("[EventHandler::OnFrontendEvent] Finished.");
@ -465,8 +535,6 @@ void EventHandler::SourceRenamedMultiHandler(void *param, calldata_t *data)
case OBS_SOURCE_TYPE_INPUT:
eventHandler->HandleInputNameChanged(source, oldSourceName, sourceName);
break;
case OBS_SOURCE_TYPE_FILTER:
break;
case OBS_SOURCE_TYPE_TRANSITION:
break;
case OBS_SOURCE_TYPE_SCENE:

View File

@ -58,6 +58,9 @@ class EventHandler
void ConnectSourceSignals(obs_source_t *source);
void DisconnectSourceSignals(obs_source_t *source);
void ConnectFilterSignals(obs_source_t *filter);
void DisconnectFilterSignals(obs_source_t *filter);
void BroadcastEvent(uint64_t requiredIntent, std::string eventType, json eventData = nullptr, uint8_t rpcVersion = 0);
// Signal handler: frontend
@ -136,4 +139,11 @@ class EventHandler
static void HandleMediaInputPlaybackStarted(void *param, calldata_t *data); // Direct callback
static void HandleMediaInputPlaybackEnded(void *param, calldata_t *data); // Direct callback
void HandleMediaInputActionTriggered(obs_source_t *source, ObsMediaInputAction action);
// Filters
static void HandleSourceFilterNameChanged(void *param, calldata_t *data); // Direct callback
static void HandleSourceFilterCreated(void *param, calldata_t *data); // Direct callback
static void HandleSourceFilterRemoved(void *param, calldata_t *data); // Direct callback
static void HandleSourceFilterListReindexed(void *param, calldata_t *data); // Direct callback
static void HandleSourceFilterEnableStateChanged(void *param, calldata_t *data); // Direct callback
};

View File

@ -18,3 +18,174 @@ with this program. If not, see <https://www.gnu.org/licenses/>
*/
#include "EventHandler.h"
/**
* A filter has been added to a source.
*
* @dataField sourceName | String | Name of the source the filter was added to
* @dataField filterName | String | Name of the filter
* @dataField filterKind | String | The kind of the filter
* @dataField filterIndex | Number | Index position of the filter
* @dataField filterSettings | Object | The settings configured to the filter when it was created
* @dataField defaultFilterSettings | Object | The default settings for the filter
*
* @eventType SourceFilterCreated
* @eventSubscription Filters
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.0.0
* @api events
* @category filters
*/
void EventHandler::HandleSourceFilterCreated(void *param, calldata_t *data)
{
auto eventHandler = static_cast<EventHandler*>(param);
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "filter");
if (!(source && filter))
return;
eventHandler->ConnectFilterSignals(filter);
std::string filterKind = obs_source_get_id(filter);
OBSDataAutoRelease filterSettings = obs_source_get_settings(filter);
OBSDataAutoRelease defaultFilterSettings = obs_get_source_defaults(filterKind.c_str());
json eventData;
eventData["sourceName"] = obs_source_get_name(source);
eventData["filterName"] = obs_source_get_name(filter);
eventData["filterKind"] = filterKind;
eventData["filterIndex"] = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter);
eventData["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings);
eventData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultFilterSettings, true);
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterCreated", eventData);
}
/**
* A filter has been removed from a source.
*
* @dataField sourceName | String | Name of the source the filter was on
* @dataField filterName | String | Name of the filter
*
* @eventType SourceFilterRemoved
* @eventSubscription Filters
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.0.0
* @api events
* @category filters
*/
void EventHandler::HandleSourceFilterRemoved(void *param, calldata_t *data)
{
auto eventHandler = static_cast<EventHandler*>(param);
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "filter");
if (!(source && filter))
return;
eventHandler->DisconnectFilterSignals(filter);
json eventData;
eventData["sourceName"] = obs_source_get_name(source);
eventData["filterName"] = obs_source_get_name(filter);
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterRemoved", eventData);
}
/**
* A source's filter list has been reindexed.
*
* @dataField sourceName | String | Name of the source
* @dataField filters | Array<Object> | Array of filter objects
*
* @eventType SourceFilterListReindexed
* @eventSubscription Filters
* @complexity 3
* @rpcVersion -1
* @initialVersion 5.0.0
* @api events
* @category filters
*/
void EventHandler::HandleSourceFilterListReindexed(void *param, calldata_t *data)
{
auto eventHandler = static_cast<EventHandler*>(param);
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
if (!source)
return;
json eventData;
eventData["sourceName"] = obs_source_get_name(source);
eventData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source);
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterListReindexed", eventData);
}
/**
* A source filter's enable state has changed.
*
* @dataField sourceName | String | Name of the source the filter is on
* @dataField filterName | String | Name of the filter
* @dataField filterEnabled | Boolean | Whether the filter is enabled
*
* @eventType SourceFilterEnableStateChanged
* @eventSubscription Filters
* @complexity 3
* @rpcVersion -1
* @initialVersion 5.0.0
* @api events
* @category filters
*/
void EventHandler::HandleSourceFilterEnableStateChanged(void *param, calldata_t *data)
{
auto eventHandler = static_cast<EventHandler*>(param);
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "source");
if (!filter)
return;
// Not OBSSourceAutoRelease as get_parent doesn't increment refcount
obs_source_t *source = obs_filter_get_parent(filter);
if (!source)
return;
bool filterEnabled = calldata_bool(data, "enabled");
json eventData;
eventData["sourceName"] = obs_source_get_name(source);
eventData["filterName"] = obs_source_get_name(filter);
eventData["filterEnabled"] = filterEnabled;
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterEnableStateChanged", eventData);
}
/**
* The name of a source filter has changed.
*
* @dataField sourceName | String | The source the filter is on
* @dataField oldFilterName | String | Old name of the filter
* @dataField filterName | String | New name of the filter
*
* @eventType SourceFilterNameChanged
* @eventSubscription Filters
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.0.0
* @api events
* @category filters
*/
void EventHandler::HandleSourceFilterNameChanged(void *param, calldata_t *data)
{
auto eventHandler = static_cast<EventHandler*>(param);
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "source");
if (!filter)
return;
json eventData;
eventData["sourceName"] = obs_source_get_name(obs_filter_get_parent(filter));
eventData["oldFilterName"] = calldata_string(data, "prev_name");
eventData["filterName"] = calldata_string(data, "new_name");
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterNameChanged", eventData);
}

View File

@ -111,7 +111,14 @@ const std::unordered_map<std::string, RequestMethodHandler> RequestHandler::_han
{"SetTBarPosition", &RequestHandler::SetTBarPosition},
// Filters
{"GetSourceFilterList", &RequestHandler::GetSourceFilterList},
{"CreateSourceFilter", &RequestHandler::CreateSourceFilter},
{"RemoveSourceFilter", &RequestHandler::RemoveSourceFilter},
{"GetSourceFilterDefaultSettings", &RequestHandler::GetSourceFilterDefaultSettings},
{"GetSourceFilter", &RequestHandler::GetSourceFilter},
{"SetSourceFilterIndex", &RequestHandler::SetSourceFilterIndex},
{"SetSourceFilterSettings", &RequestHandler::SetSourceFilterSettings},
{"SetSourceFilterEnabled", &RequestHandler::SetSourceFilterEnabled},
// Scene Items
{"GetSceneItemList", &RequestHandler::GetSceneItemList},

View File

@ -129,7 +129,14 @@ class RequestHandler {
RequestResult SetTBarPosition(const Request&);
// Filters
RequestResult GetSourceFilterList(const Request&);
RequestResult CreateSourceFilter(const Request&);
RequestResult RemoveSourceFilter(const Request&);
RequestResult GetSourceFilterDefaultSettings(const Request&);
RequestResult GetSourceFilter(const Request&);
RequestResult SetSourceFilterIndex(const Request&);
RequestResult SetSourceFilterSettings(const Request&);
RequestResult SetSourceFilterEnabled(const Request&);
// Scene Items
RequestResult GetSceneItemList(const Request&);

View File

@ -19,6 +19,145 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include "RequestHandler.h"
/**
* Gets an array of all of a source's filters.
*
* @requestField sourceName | String | Name of the source
*
* @responseField filters | Array<Object> | Array of filters
*
* @requestType GetSourceFilterList
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category filters
*/
RequestResult RequestHandler::GetSourceFilterList(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
if(!source)
return RequestResult::Error(statusCode, comment);
json responseData;
responseData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source);
return RequestResult::Success(responseData);
}
/**
* Creates a new filter, adding it to the specified source.
*
* @requestField sourceName | String | Name of the source to add the filter to
* @requestField filterName | String | Name of the new filter to be created
* @requestField filterKind | String | The kind of filter to be created
* @requestField ?filterSettings | Object | Settings object to initialize the filter with | Default settings used
*
* @requestType CreateSourceFilter
* @complexity 3
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category filters
*/
RequestResult RequestHandler::CreateSourceFilter(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
if (!(source && request.ValidateString("filterName", statusCode, comment) && request.ValidateString("filterKind", statusCode, comment)))
return RequestResult::Error(statusCode, comment);
std::string filterName = request.RequestData["filterName"];
OBSSourceAutoRelease existingFilter = obs_source_get_filter_by_name(source, filterName.c_str());
if (existingFilter)
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A filter already exists by that name.");
std::string filterKind = request.RequestData["filterKind"];
auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList();
if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end())
return RequestResult::Error(RequestStatus::InvalidFilterKind, "Your specified filter kind is not supported by OBS. Check that any necessary plugins are loaded.");
OBSDataAutoRelease filterSettings = nullptr;
if (request.Contains("filterSettings")) {
if (!request.ValidateOptionalObject("filterSettings", statusCode, comment, true))
return RequestResult::Error(statusCode, comment);
filterSettings = Utils::Json::JsonToObsData(request.RequestData["filterSettings"]);
}
OBSSourceAutoRelease filter = Utils::Obs::ActionHelper::CreateSourceFilter(source, filterName, filterKind, filterSettings);
if(!filter)
return RequestResult::Error(RequestStatus::ResourceCreationFailed, "Creation of the filter failed.");
return RequestResult::Success();
}
/**
* Removes a filter from a source.
*
* @requestField sourceName | String | Name of the source the filter is on
* @requestField filterName | String | Name of the filter to remove
*
* @requestType RemoveSourceFilter
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category filters
*/
RequestResult RequestHandler::RemoveSourceFilter(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);
obs_source_filter_remove(pair.source, pair.filter);
return RequestResult::Success();
}
/**
* Gets the default settings for a filter kind.
*
* @requestField filterKind | String | Filter kind to get the default settings for
*
* @responseField defaultFilterSettings | Object | Object of default settings for the filter kind
*
* @requestType GetSourceFilterDefaultSettings
* @complexity 3
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category filters
*/
RequestResult RequestHandler::GetSourceFilterDefaultSettings(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
if (!request.ValidateString("filterKind", statusCode, comment))
return RequestResult::Error(statusCode, comment);
std::string filterKind = request.RequestData["filterKind"];
auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList();
if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end())
return RequestResult::Error(RequestStatus::InvalidFilterKind);
OBSDataAutoRelease defaultSettings = obs_get_source_defaults(filterKind.c_str());
if (!defaultSettings)
return RequestResult::Error(RequestStatus::InvalidFilterKind);
json responseData;
responseData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultSettings, true);
return RequestResult::Success(responseData);
}
/**
* Gets the info for a specific source filter.
*
@ -55,3 +194,108 @@ RequestResult RequestHandler::GetSourceFilter(const Request& request)
return RequestResult::Success(responseData);
}
/**
* Sets the index position of a filter on a source.
*
* @requestField sourceName | String | Name of the source the filter is on
* @requestField filterName | String | Name of the filter
* @requestField filterIndex | Number | New index position of the filter | >= 0
*
* @requestType SetSourceFilterIndex
* @complexity 3
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category filters
*/
RequestResult RequestHandler::SetSourceFilterIndex(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
if (!(pair.filter && request.ValidateNumber("filterIndex", statusCode, comment, 0, 8192)))
return RequestResult::Error(statusCode, comment);
int filterIndex = request.RequestData["filterIndex"];
Utils::Obs::ActionHelper::SetSourceFilterIndex(pair.source, pair.filter, filterIndex);
return RequestResult::Success();
}
/**
* Sets the settings of a source filter.
*
* @requestField sourceName | String | Name of the source the filter is on
* @requestField filterName | String | Name of the filter to set the settings of
* @requestField filterSettings | Object | Object of settings to apply
* @requestField ?overlay | Boolean | True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings. | true
*
* @requestType SetSourceFilterSettings
* @complexity 3
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category filters
*/
RequestResult RequestHandler::SetSourceFilterSettings(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
if (!(pair.filter && request.ValidateObject("filterSettings", statusCode, comment, true)))
return RequestResult::Error(statusCode, comment);
// Almost identical to SetInputSettings
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["filterSettings"]);
if (!newSettings)
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "An internal data conversion operation failed. Please report this!");
if (overlay)
obs_source_update(pair.filter, newSettings);
else
obs_source_reset_settings(pair.filter, newSettings);
obs_source_update_properties(pair.filter);
return RequestResult::Success();
}
/**
* Sets the enable state of a source filter.
*
* @requestField sourceName | String | Name of the source the filter is on
* @requestField filterName | Number | Name of the filter
* @requestField filterEnabled | Boolean | New enable state of the filter
*
* @requestType SetSourceFilterEnabled
* @complexity 3
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category filters
*/
RequestResult RequestHandler::SetSourceFilterEnabled(const Request& request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
if (!(pair.filter && request.ValidateBoolean("filterEnabled", statusCode, comment)))
return RequestResult::Error(statusCode, comment);
bool filterEnabled = request.RequestData["filterEnabled"];
obs_source_set_enabled(pair.filter, filterEnabled);
return RequestResult::Success();
}

View File

@ -269,6 +269,9 @@ RequestResult RequestHandler::GetInputDefaultSettings(const Request& request)
return RequestResult::Error(statusCode, comment);
std::string inputKind = request.RequestData["inputKind"];
auto kinds = Utils::Obs::ArrayHelper::GetInputKindList();
if (std::find(kinds.begin(), kinds.end(), inputKind) == kinds.end())
return RequestResult::Error(RequestStatus::InvalidInputKind);
OBSDataAutoRelease defaultSettings = obs_get_source_defaults(inputKind.c_str());
if (!defaultSettings)

View File

@ -345,6 +345,17 @@ namespace RequestStatus {
* @api enums
*/
ResourceNotConfigurable = 606,
/**
* The specified filter (obs_source_t-OBS_SOURCE_TYPE_FILTER) had the wrong kind.
*
* @enumIdentifier InvalidFilterKind
* @enumValue 607
* @enumType RequestStatus
* @rpcVersion -1
* @initialVersion 5.0.0
* @api enums
*/
InvalidFilterKind = 607,
/**
* Creating the resource failed.

View File

@ -193,6 +193,8 @@ namespace Utils {
std::vector<json> GetListPropertyItems(obs_property_t *property);
std::vector<std::string> GetTransitionKindList();
std::vector<json> GetSceneTransitionList();
std::vector<json> GetSourceFilterList(obs_source_t *source);
std::vector<std::string> GetFilterKindList();
}
namespace ObjectHelper {
@ -209,6 +211,8 @@ namespace Utils {
namespace ActionHelper {
obs_sceneitem_t *CreateSceneItem(obs_source_t *source, obs_scene_t *scene, bool sceneItemEnabled = true, obs_transform_info *sceneItemTransform = nullptr, obs_sceneitem_crop *sceneItemCrop = nullptr); // Increments ref. Use OBSSceneItemAutoRelease
obs_sceneitem_t *CreateInput(std::string inputName, std::string inputKind, obs_data_t *inputSettings, obs_scene_t *scene, bool sceneItemEnabled = true); // Increments ref. Use OBSSceneItemAutoRelease
obs_source_t *CreateSourceFilter(obs_source_t *source, std::string filterName, std::string filterKind, obs_data_t *filterSettings); // Increments source ref. Use OBSSourceAutoRelease
void SetSourceFilterIndex(obs_source_t *source, obs_source_t *filter, size_t index);
}
}
}

View File

@ -87,3 +87,30 @@ obs_sceneitem_t *Utils::Obs::ActionHelper::CreateInput(std::string inputName, st
return ret;
}
obs_source_t *Utils::Obs::ActionHelper::CreateSourceFilter(obs_source_t *source, std::string filterName, std::string filterKind, obs_data_t *filterSettings)
{
obs_source_t *filter = obs_source_create_private(filterKind.c_str(), filterName.c_str(), filterSettings);
if (!filter)
return nullptr;
obs_source_filter_add(source, filter);
return filter;
}
void Utils::Obs::ActionHelper::SetSourceFilterIndex(obs_source_t *source, obs_source_t *filter, size_t index)
{
size_t currentIndex = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter);
obs_order_movement direction = index > currentIndex ? OBS_ORDER_MOVE_DOWN : OBS_ORDER_MOVE_UP;
while(currentIndex != index) {
obs_source_filter_set_order(source, filter, direction);
if (direction == OBS_ORDER_MOVE_DOWN)
currentIndex++;
else
currentIndex--;
}
}

View File

@ -276,3 +276,38 @@ std::vector<json> Utils::Obs::ArrayHelper::GetSceneTransitionList()
return ret;
}
std::vector<std::string> Utils::Obs::ArrayHelper::GetFilterKindList()
{
std::vector<std::string> ret;
size_t idx = 0;
const char *kind;
while(obs_enum_filter_types(idx++, &kind))
ret.push_back(kind);
return ret;
}
std::vector<json> Utils::Obs::ArrayHelper::GetSourceFilterList(obs_source_t *source)
{
std::vector<json> filters;
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param) {
auto filters = reinterpret_cast<std::vector<json>*>(param);
json filterJson;
filterJson["filterEnabled"] = obs_source_enabled(filter);
filterJson["filterIndex"] = filters->size();
filterJson["filterKind"] = obs_source_get_id(filter);
filterJson["filterName"] = obs_source_get_name(filter);
OBSDataAutoRelease filterSettings = obs_source_get_settings(filter);
filterJson["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings);
filters->push_back(filterJson);
};
obs_source_enum_filters(source, enumFilters, &filters);
return filters;
}