diff --git a/js/module.d.ts b/js/module.d.ts index 5b27b3613..c883fa437 100644 --- a/js/module.d.ts +++ b/js/module.d.ts @@ -458,7 +458,7 @@ export interface IInput extends ISource { sendFocus(focus: boolean): void; sendKeyClick(eventData: IKeyEvent, keyUp: boolean): void; setFilterOrder(filter: IFilter, movement: EOrderMovement): void; - setFilterOrder(filter: IFilter, movement: EOrderMovement): void; + setFilterPosition(filter: IFilter, position: number): void; readonly filters: IFilter[]; readonly width: number; readonly height: number; diff --git a/js/module.ts b/js/module.ts index 2609b442f..55782f635 100644 --- a/js/module.ts +++ b/js/module.ts @@ -819,11 +819,11 @@ export interface IInput extends ISource { setFilterOrder(filter: IFilter, movement: EOrderMovement): void; /** - * Move a filter up, down, top, or bottom in the filter list. + * Set a filter position in the filter list. * @param filter - The filter to move within the input source. - * @param movement - The movement to make within the list. + * @param position - The position to make within the list. */ - setFilterOrder(filter: IFilter, movement: EOrderMovement): void; + setFilterPosition(filter: IFilter, position: number): void; /** diff --git a/obs-studio-client/source/input.cpp b/obs-studio-client/source/input.cpp index 0096ca0f5..3bf09daed 100644 --- a/obs-studio-client/source/input.cpp +++ b/obs-studio-client/source/input.cpp @@ -47,6 +47,7 @@ Napi::Object osn::Input::Init(Napi::Env env, Napi::Object exports) { InstanceMethod("addFilter", &osn::Input::AddFilter), InstanceMethod("removeFilter", &osn::Input::RemoveFilter), InstanceMethod("setFilterOrder", &osn::Input::SetFilterOrder), + InstanceMethod("setFilterPosition", &osn::Input::SetFilterPosition), InstanceMethod("findFilter", &osn::Input::FindFilter), InstanceMethod("copyFilters", &osn::Input::CopyFilters), @@ -675,6 +676,26 @@ Napi::Value osn::Input::SetFilterOrder(const Napi::CallbackInfo& info) return info.Env().Undefined(); } +Napi::Value osn::Input::SetFilterPosition(const Napi::CallbackInfo& info) +{ + osn::Filter* objfilter = Napi::ObjectWrap::Unwrap(info[0].ToObject()); + uint32_t position = info[1].ToNumber().Uint32Value(); + + auto conn = GetConnection(info); + if (!conn) + return info.Env().Undefined(); + + conn->call( + "Input", "PositionFilter", {ipc::value(this->sourceId), ipc::value(objfilter->sourceId), ipc::value(position)}); + + SourceDataInfo* sdi = CacheManager::getInstance().Retrieve(this->sourceId); + if (sdi) { + sdi->filtersOrderChanged = true; + } + + return info.Env().Undefined(); +} + Napi::Value osn::Input::FindFilter(const Napi::CallbackInfo& info) { std::string name = info[0].ToString().Utf8Value(); diff --git a/obs-studio-client/source/input.hpp b/obs-studio-client/source/input.hpp index fde7aee98..42727a9a3 100644 --- a/obs-studio-client/source/input.hpp +++ b/obs-studio-client/source/input.hpp @@ -43,6 +43,7 @@ namespace osn Napi::Value AddFilter(const Napi::CallbackInfo& info); Napi::Value RemoveFilter(const Napi::CallbackInfo& info); Napi::Value SetFilterOrder(const Napi::CallbackInfo& info); + Napi::Value SetFilterPosition(const Napi::CallbackInfo& info); Napi::Value FindFilter(const Napi::CallbackInfo& info); Napi::Value CopyFilters(const Napi::CallbackInfo& info); diff --git a/obs-studio-server/source/osn-input.cpp b/obs-studio-server/source/osn-input.cpp index 7390e1069..9d2c7c3fe 100644 --- a/obs-studio-server/source/osn-input.cpp +++ b/obs-studio-server/source/osn-input.cpp @@ -97,6 +97,8 @@ void osn::Input::Register(ipc::server& srv) "RemoveFilter", std::vector{ipc::type::UInt64, ipc::type::UInt64}, RemoveFilter)); cls->register_function(std::make_shared( "MoveFilter", std::vector{ipc::type::UInt64, ipc::type::UInt64, ipc::type::UInt32}, MoveFilter)); + cls->register_function(std::make_shared( + "PositionFilter", std::vector{ipc::type::UInt64, ipc::type::UInt64, ipc::type::UInt32}, PositionFilter)); cls->register_function(std::make_shared( "FindFilter", std::vector{ipc::type::UInt64, ipc::type::String}, FindFilter)); cls->register_function(std::make_shared( @@ -632,6 +634,30 @@ void osn::Input::MoveFilter( AUTO_DEBUG; } +void osn::Input::PositionFilter( + void* data, + const int64_t id, + const std::vector& args, + std::vector& rval) +{ + obs_source_t* input = osn::Source::Manager::GetInstance().find(args[0].value_union.ui64); + if (!input) { + PRETTY_ERROR_RETURN(ErrorCode::InvalidReference, "Input reference is not valid."); + } + + obs_source_t* filter = osn::Source::Manager::GetInstance().find(args[1].value_union.ui64); + if (!filter) { + PRETTY_ERROR_RETURN(ErrorCode::InvalidReference, "Filter reference is not valid."); + } + + size_t position = (size_t)args[2].value_union.ui32; + + obs_source_filter_set_position(input, filter, position); + + rval.push_back(ipc::value((uint64_t)ErrorCode::Ok)); + AUTO_DEBUG; +} + void osn::Input::FindFilter( void* data, const int64_t id, @@ -676,6 +702,7 @@ void osn::Input::GetFilters( std::vector* rval = reinterpret_cast*>(data); uint64_t id = osn::Source::Manager::GetInstance().find(filter); + if (id != UINT64_MAX) { rval->push_back(id); } diff --git a/obs-studio-server/source/osn-input.hpp b/obs-studio-server/source/osn-input.hpp index ef83787e7..482f5df6a 100644 --- a/obs-studio-server/source/osn-input.hpp +++ b/obs-studio-server/source/osn-input.hpp @@ -128,6 +128,11 @@ namespace osn const int64_t id, const std::vector& args, std::vector& rval); + static void PositionFilter( + void* data, + const int64_t id, + const std::vector& args, + std::vector& rval); static void FindFilter( void* data, const int64_t id, diff --git a/tests/osn-tests/src/test_osn_input.ts b/tests/osn-tests/src/test_osn_input.ts index f76f474eb..e77f35e6f 100644 --- a/tests/osn-tests/src/test_osn_input.ts +++ b/tests/osn-tests/src/test_osn_input.ts @@ -563,7 +563,7 @@ describe(testName, () => { }); }); - it('Change the order of filters in the list', () => { + it('Change the order of filters in the list by moving', () => { // Creating source const input = osn.InputFactory.create(EOBSInputTypes.ImageSource, 'test_source'); @@ -620,6 +620,59 @@ describe(testName, () => { input.release(); }); + it('Change the order of filters in the list by positioning', () => { + // Creating source + const input = osn.InputFactory.create(EOBSInputTypes.FFMPEGSource, 'ffmpeg_source'); + + // Checking if source was created correctly + expect(input).to.not.equal(undefined, GetErrorMessage(ETestErrorMsg.CreateInput, EOBSInputTypes.FFMPEGSource)); + expect(input.id).to.equal(EOBSInputTypes.FFMPEGSource, GetErrorMessage(ETestErrorMsg.InputId, EOBSInputTypes.FFMPEGSource)); + expect(input.name).to.equal('ffmpeg_source', GetErrorMessage(ETestErrorMsg.InputName, EOBSInputTypes.FFMPEGSource)); + + // Creating filters + const filter1 = osn.FilterFactory.create(EOBSFilterTypes.Color, 'filter1'); + const filter2 = osn.FilterFactory.create(EOBSFilterTypes.Crop, 'filter2'); + const filter3 = osn.FilterFactory.create(EOBSFilterTypes.Gain, 'filter3'); + const filter4 = osn.FilterFactory.create(EOBSFilterTypes.GPUDelay, 'filter4'); + + // Checking if filters were created correctly + expect(filter1).to.not.equal(undefined, GetErrorMessage(ETestErrorMsg.CreateFilter, EOBSFilterTypes.Color)); + expect(filter2).to.not.equal(undefined, GetErrorMessage(ETestErrorMsg.CreateFilter, EOBSFilterTypes.Crop)); + expect(filter3).to.not.equal(undefined, GetErrorMessage(ETestErrorMsg.CreateFilter, EOBSFilterTypes.Gain)); + expect(filter4).to.not.equal(undefined, GetErrorMessage(ETestErrorMsg.CreateFilter, EOBSFilterTypes.GPUDelay)); + + // Adding filters to source + input.addFilter(filter1); + input.addFilter(filter2); + input.addFilter(filter3); + input.addFilter(filter4); + + // Checking if filters are in the right position + expect(input.filters[0].name).to.equal('filter1', GetErrorMessage(ETestErrorMsg.FilterInsert, EOBSFilterTypes.Color)); + expect(input.filters[1].name).to.equal('filter2', GetErrorMessage(ETestErrorMsg.FilterInsert, EOBSFilterTypes.Crop)); + expect(input.filters[2].name).to.equal('filter3', GetErrorMessage(ETestErrorMsg.FilterInsert, EOBSFilterTypes.Gain)); + expect(input.filters[3].name).to.equal('filter4', GetErrorMessage(ETestErrorMsg.FilterInsert, EOBSFilterTypes.GPUDelay)); + + // Changing filter order down + input.setFilterOrder(filter1, osn.EOrderMovement.Down); + // Checking if filter is in the right position + expect(input.filters[1].name).to.equal('filter1', GetErrorMessage(ETestErrorMsg.MoveFilterDown, EOBSFilterTypes.Color)); + + // Change filter position + input.setFilterPosition(filter1, 2); + + // Checking if filter is in the right position + expect(input.filters[2].name).to.equal('filter1', GetErrorMessage(ETestErrorMsg.PositionFilter, EOBSFilterTypes.Color)); + + // Removing all filters + input.filters.forEach(function(filter) { + input.removeFilter(filter); + filter.release(); + }); + + input.release(); + }); + it('Fail test - Try to find an input that does not exist', () => { let inputFromName: IInput; diff --git a/tests/osn-tests/util/error_messages.ts b/tests/osn-tests/util/error_messages.ts index 7f426fb77..c4773dd4d 100644 --- a/tests/osn-tests/util/error_messages.ts +++ b/tests/osn-tests/util/error_messages.ts @@ -86,6 +86,8 @@ export const enum ETestErrorMsg { MonitoringType = 'Failed to update monitoring type of input %VALUE1%', FindFilter = 'Did not found filter %VALUE1% in input %VALUE2%', RemoveFilter = 'Not all filters were removed', + PositionFilter = 'Failed to move filter %VALUE1% into position', + FilterInsert = 'Failed to insert a filter %VALUE1% into source', MoveFilterDown = 'Failed to move filter %VALUE1% down', MoveFilterUp = 'Failed to move filter %VALUE1% up', MoveFilterBottom = 'Failed to move filter %VALUE1% to bottom',