diff --git a/CMakeLists.txt b/CMakeLists.txt index fb650938..ac7852a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1313,18 +1313,32 @@ list(APPEND PROJECT_PRIVATE_SOURCE "source/obs/gs/gs-vertex.cpp" "source/obs/gs/gs-vertexbuffer.hpp" "source/obs/gs/gs-vertexbuffer.cpp" - "source/obs/obs-encoder-factory.hpp" - "source/obs/obs-encoder-factory.cpp" "source/obs/obs-signal-handler.hpp" "source/obs/obs-signal-handler.cpp" - "source/obs/obs-source.hpp" - "source/obs/obs-source.cpp" - "source/obs/obs-source-factory.hpp" - "source/obs/obs-source-factory.cpp" "source/obs/obs-source-tracker.hpp" "source/obs/obs-source-tracker.cpp" "source/obs/obs-tools.hpp" "source/obs/obs-tools.cpp" + + # obs_encoder_info_t, obs_encoder_t, obs_weak_encoder_t + "source/obs/obs-encoder-factory.hpp" + "source/obs/obs-encoder-factory.cpp" + + # obs_source_info_t, obs_source_t, obs_weak_source_t + "source/obs/obs-source-factory.hpp" + "source/obs/obs-source-factory.cpp" + "source/obs/obs-source-info.hpp" + "source/obs/obs-source-info.cpp" + "source/obs/obs-source.hpp" + "source/obs/obs-source.cpp" + "source/obs/obs-source-active-child.hpp" + "source/obs/obs-source-active-child.cpp" + "source/obs/obs-source-active-reference.hpp" + "source/obs/obs-source-active-reference.cpp" + "source/obs/obs-source-showing-reference.hpp" + "source/obs/obs-source-showing-reference.cpp" + "source/obs/obs-weak-source.hpp" + "source/obs/obs-weak-source.cpp" ) list(APPEND PROJECT_DATA "data/effects/color_conversion_rgb_hsl.effect" diff --git a/source/obs/obs-source-active-child.cpp b/source/obs/obs-source-active-child.cpp new file mode 100644 index 00000000..c876eb10 --- /dev/null +++ b/source/obs/obs-source-active-child.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2022 Michael Fabian Dirks + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "obs-source-active-child.hpp" diff --git a/source/obs/obs-source-active-child.hpp b/source/obs/obs-source-active-child.hpp new file mode 100644 index 00000000..736f1dfc --- /dev/null +++ b/source/obs/obs-source-active-child.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 Michael Fabian Dirks + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include "common.hpp" +#include "obs-source.hpp" +#include "obs-tools.hpp" +#include "obs-weak-source.hpp" + +namespace streamfx::obs { + class source_active_child { + ::streamfx::obs::weak_source _parent; + ::streamfx::obs::weak_source _child; + + public: + ~source_active_child() + { + auto parent = _parent.lock(); + auto child = _child.lock(); + if (parent && child) { + obs_source_remove_active_child(parent, child); + } + } + source_active_child(::streamfx::obs::source const& parent, ::streamfx::obs::source const& child) + : _parent(parent), _child(child) + { + if (::streamfx::obs::tools::source_find_source(child, parent)) { + throw std::runtime_error("Child contains Parent"); + } else if (!obs_source_add_active_child(parent, child)) { + throw std::runtime_error("Child contains Parent"); + } + } + }; +} // namespace streamfx::obs diff --git a/source/obs/obs-source-active-reference.cpp b/source/obs/obs-source-active-reference.cpp new file mode 100644 index 00000000..394c1997 --- /dev/null +++ b/source/obs/obs-source-active-reference.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2022 Michael Fabian Dirks + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "obs-source-active-reference.hpp" diff --git a/source/obs/obs-source-active-reference.hpp b/source/obs/obs-source-active-reference.hpp new file mode 100644 index 00000000..c5233d48 --- /dev/null +++ b/source/obs/obs-source-active-reference.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 Michael Fabian Dirks + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include "common.hpp" +#include "obs-source.hpp" +#include "obs-weak-source.hpp" + +namespace streamfx::obs { + class source_active_reference { + ::streamfx::obs::weak_source _target; + + public: + ~source_active_reference() + { + auto v = _target.lock(); + if (v) { + v.decrement_active(); + } + } + source_active_reference(::streamfx::obs::source& source) : _target(source) + { + source.increment_active(); + } + + public: + static FORCE_INLINE std::shared_ptr + add_active_reference(::streamfx::obs::source& source) + { + return std::make_shared(source); + } + }; +} // namespace streamfx::obs diff --git a/source/obs/obs-source-info.cpp b/source/obs/obs-source-info.cpp new file mode 100644 index 00000000..e69de29b diff --git a/source/obs/obs-source-info.hpp b/source/obs/obs-source-info.hpp new file mode 100644 index 00000000..e69de29b diff --git a/source/obs/obs-source-showing-reference.cpp b/source/obs/obs-source-showing-reference.cpp new file mode 100644 index 00000000..2f71f103 --- /dev/null +++ b/source/obs/obs-source-showing-reference.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2022 Michael Fabian Dirks + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "obs-source-showing-reference.hpp" diff --git a/source/obs/obs-source-showing-reference.hpp b/source/obs/obs-source-showing-reference.hpp new file mode 100644 index 00000000..b14b78bc --- /dev/null +++ b/source/obs/obs-source-showing-reference.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 Michael Fabian Dirks + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include "common.hpp" +#include "obs-source.hpp" +#include "obs-tools.hpp" +#include "obs-weak-source.hpp" + +namespace streamfx::obs { + class source_showing_reference { + ::streamfx::obs::weak_source _target; + + public: + ~source_showing_reference() + { + auto v = _target.lock(); + if (v) { + v.decrement_showing(); + } + } + source_showing_reference(::streamfx::obs::source& source) : _target(source) + { + source.increment_showing(); + } + + public: + static FORCE_INLINE std::shared_ptr + add_showing_reference(::streamfx::obs::source& source) + { + return std::make_shared(source); + } + }; +} // namespace streamfx::obs diff --git a/source/obs/obs-source.cpp b/source/obs/obs-source.cpp index f578f585..385120e0 100644 --- a/source/obs/obs-source.cpp +++ b/source/obs/obs-source.cpp @@ -18,816 +18,3 @@ */ #include "obs-source.hpp" -#include -#include "plugin.hpp" - -void streamfx::obs::deprecated_source::handle_destroy(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - - obs_source_t* source; - if (!calldata_get_ptr(calldata, "source", &source)) { - return; - } - - if (self->_self == source) { - self->_self = nullptr; - } - - if (self->events.destroy) { - return; - } - self->events.destroy(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_remove(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.remove) { - return; - } - self->events.remove(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_save(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.save) { - return; - } - self->events.save(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_load(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.load) { - return; - } - self->events.load(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_activate(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.activate) { - return; - } - self->events.activate(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_deactivate(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.deactivate) { - return; - } - self->events.deactivate(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_show(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.show) { - return; - } - self->events.show(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_hide(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.hide) { - return; - } - self->events.hide(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_enable(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.enable) { - return; - } - - bool enabled = false; - if (!calldata_get_bool(calldata, "enabled", &enabled)) { - return; - } - - self->events.enable(self, enabled); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_push_to_mute_changed(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.push_to_mute_changed) { - return; - } - - bool enabled = false; - if (!calldata_get_bool(calldata, "enabled", &enabled)) { - return; - } - - self->events.push_to_mute_changed(self, enabled); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_push_to_mute_delay(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.push_to_mute_delay) { - return; - } - - long long delay; - if (!calldata_get_int(calldata, "delay", &delay)) { - return; - } - - self->events.push_to_mute_delay(self, delay); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_push_to_talk_changed(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.push_to_talk_changed) { - return; - } - - bool enabled = false; - if (!calldata_get_bool(calldata, "enabled", &enabled)) { - return; - } - - self->events.push_to_talk_changed(self, enabled); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_push_to_talk_delay(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.push_to_talk_delay) { - return; - } - - long long delay; - if (!calldata_get_int(calldata, "delay", &delay)) { - return; - } - - self->events.push_to_talk_delay(self, delay); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_rename(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.enable) { - return; - } - - const char* new_name; - if (!calldata_get_string(calldata, "new_name", &new_name)) { - return; - } - - const char* prev_name; - if (!calldata_get_string(calldata, "prev_name", &prev_name)) { - return; - } - - self->events.rename(self, std::string(new_name ? new_name : ""), std::string(prev_name ? prev_name : "")); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_update_properties(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.update_properties) { - return; - } - self->events.update_properties(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_update_flags(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.update_flags) { - return; - } - - long long flags; - if (!calldata_get_int(calldata, "flags", &flags)) { - return; - } - - self->events.update_flags(self, flags); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_mute(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.mute) { - return; - } - - bool muted; - if (!calldata_get_bool(calldata, "muted", &muted)) { - return; - } - - self->events.mute(self, muted); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_volume(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.volume) { - return; - } - - double volume; - if (!calldata_get_float(calldata, "volume", &volume)) { - return; - } - - self->events.volume(self, volume); - - calldata_set_float(calldata, "volume", volume); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_audio_sync(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.audio_sync) { - return; - } - - long long mixers; - if (!calldata_get_int(calldata, "offset", &mixers)) { - return; - } - - self->events.audio_sync(self, mixers); - - calldata_set_int(calldata, "offset", mixers); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_audio_mixers(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.audio_mixers) { - return; - } - - long long mixers; - if (!calldata_get_int(calldata, "mixers", &mixers)) { - return; - } - - self->events.audio_mixers(self, mixers); - - calldata_set_int(calldata, "mixers", mixers); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_audio_data(void* p, obs_source_t*, const audio_data* audio, - bool muted) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.audio) { - return; - } - - self->events.audio(self, audio, muted); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_filter_add(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.filter_add) { - return; - } - - obs_source_t* filter; - if (!calldata_get_ptr(calldata, "filter", &filter)) { - return; - } - - self->events.filter_add(self, filter); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_filter_remove(void* p, calldata_t* calldata) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.filter_remove) { - return; - } - - obs_source_t* filter; - if (!calldata_get_ptr(calldata, "filter", &filter)) { - return; - } - - self->events.filter_remove(self, filter); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_reorder_filters(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.reorder_filters) { - return; - } - self->events.reorder_filters(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_transition_start(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.transition_start) { - return; - } - self->events.transition_start(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_transition_video_stop(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.transition_video_stop) { - return; - } - self->events.transition_video_stop(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -void streamfx::obs::deprecated_source::handle_transition_stop(void* p, calldata_t*) noexcept -try { - streamfx::obs::deprecated_source* self = reinterpret_cast(p); - if (!self->events.transition_stop) { - return; - } - self->events.transition_stop(self); -} catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); -} catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); -} - -streamfx::obs::deprecated_source::~deprecated_source() -{ -#ifdef auto_signal_d -#undef auto_signal_d -#endif -#define auto_signal_d(SIGNAL) this->events.SIGNAL.clear() - auto_signal_d(destroy); - auto_signal_d(remove); - auto_signal_d(save); - auto_signal_d(load); - auto_signal_d(activate); - auto_signal_d(deactivate); - auto_signal_d(show); - auto_signal_d(hide); - auto_signal_d(mute); - auto_signal_d(push_to_mute_changed); - auto_signal_d(push_to_mute_delay); - auto_signal_d(push_to_talk_changed); - auto_signal_d(push_to_talk_delay); - auto_signal_d(enable); - auto_signal_d(rename); - auto_signal_d(volume); - auto_signal_d(update_properties); - auto_signal_d(update_flags); - auto_signal_d(audio_sync); - auto_signal_d(audio_mixers); - auto_signal_d(audio); - auto_signal_d(filter_add); - auto_signal_d(filter_remove); - auto_signal_d(reorder_filters); - auto_signal_d(transition_start); - auto_signal_d(transition_video_stop); - auto_signal_d(transition_stop); -#undef auto_signal_d - - if (this->_track_ownership && this->_self) { - obs_source_release(this->_self); - } - this->_self = nullptr; -} - -streamfx::obs::deprecated_source::deprecated_source() -{ -#ifdef auto_signal_c -#undef auto_signal_c -#endif -#define auto_signal_c(SIGNAL) \ - { \ - this->events.SIGNAL.set_listen_callback([this]() noexcept { \ - if (!this->_self) \ - return; \ - auto sh = obs_source_get_signal_handler(this->_self); \ - if (sh) { \ - signal_handler_connect(sh, "" #SIGNAL, obs::deprecated_source::handle_##SIGNAL, this); \ - } \ - }); \ - this->events.SIGNAL.set_silence_callback([this]() noexcept { \ - if (!this->_self) \ - return; \ - auto sh = obs_source_get_signal_handler(this->_self); \ - if (sh) { \ - signal_handler_disconnect(sh, "" #SIGNAL, obs::deprecated_source::handle_##SIGNAL, this); \ - } \ - }); \ - } - auto_signal_c(destroy) auto_signal_c(remove) auto_signal_c(save) auto_signal_c(load) auto_signal_c(activate) - auto_signal_c(deactivate) auto_signal_c(show) auto_signal_c(hide) auto_signal_c(mute) - auto_signal_c(push_to_mute_changed) auto_signal_c(push_to_mute_delay) auto_signal_c(push_to_talk_changed) - auto_signal_c(push_to_talk_delay) auto_signal_c(enable) auto_signal_c(rename) auto_signal_c(volume) - auto_signal_c(update_properties) auto_signal_c(update_flags) auto_signal_c(audio_sync) - auto_signal_c(audio_mixers) auto_signal_c(filter_add) auto_signal_c(filter_remove) - auto_signal_c(reorder_filters) auto_signal_c(transition_start) - auto_signal_c(transition_video_stop) auto_signal_c(transition_stop) -#undef auto_signal_c - - // libOBS unfortunately does not use the event system for audio data callbacks, which is kind of odd as most other - // things do. So instead we'll have to manually deal with it for now. - { - this->events.audio.set_listen_callback([this]() noexcept { - if (!this->_self) - return; - obs_source_add_audio_capture_callback(this->_self, streamfx::obs::deprecated_source::handle_audio_data, - this); - }); - this->events.audio.set_silence_callback([this]() noexcept { - if (!this->_self) - return; - obs_source_remove_audio_capture_callback(this->_self, streamfx::obs::deprecated_source::handle_audio_data, - this); - }); - } -} - -streamfx::obs::deprecated_source::deprecated_source(std::string name, bool ptrack_ownership, bool add_reference) - : ::streamfx::obs::deprecated_source::deprecated_source() -{ - this->_self = obs_get_source_by_name(name.c_str()); - if (!this->_self) { - throw std::runtime_error("source with name not found"); - } - - this->_track_ownership = ptrack_ownership; - if (!add_reference) { - obs_source_release(this->_self); - } -} - -streamfx::obs::deprecated_source::deprecated_source(obs_source_t* source, bool ptrack_ownership, bool add_reference) - : ::streamfx::obs::deprecated_source::deprecated_source() -{ - this->_self = source; - if (!this->_self) { - throw std::invalid_argument("source must not be null"); - } - - this->_track_ownership = ptrack_ownership; - if (add_reference) { - obs_source_addref(this->_self); - } -} -/* -obs::deprecated_source::deprecated_source(deprecated_source const& other) -{ - this->_self = other._self; - this->_track_ownership = other._track_ownership; - - if (this->_track_ownership) { - obs_source_addref(this->_self); - } - -#ifdef auto_signal_c -#undef auto_signal_c -#endif -#define auto_signal_c(SIGNAL) this->events.SIGNAL = other.events.SIGNAL - auto_signal_c(destroy); - auto_signal_c(remove); - auto_signal_c(save); - auto_signal_c(load); - auto_signal_c(activate); - auto_signal_c(deactivate); - auto_signal_c(show); - auto_signal_c(hide); - auto_signal_c(mute); - auto_signal_c(push_to_mute_changed); - auto_signal_c(push_to_mute_delay); - auto_signal_c(push_to_talk_changed); - auto_signal_c(push_to_talk_delay); - auto_signal_c(enable); - auto_signal_c(rename); - auto_signal_c(volume); - auto_signal_c(update_properties); - auto_signal_c(update_flags); - auto_signal_c(audio_sync); - auto_signal_c(audio_mixers); - auto_signal_c(audio); - auto_signal_c(filter_add); - auto_signal_c(filter_remove); - auto_signal_c(reorder_filters); - auto_signal_c(transition_start); - auto_signal_c(transition_video_stop); - auto_signal_c(transition_stop); -#undef auto_signal_c -} - -obs::deprecated_source& obs::deprecated_source::operator=(deprecated_source const& other) -{ - if (this == &other) { - return *this; - } - - // Release previous source. - if (this->_self && this->_track_ownership) { - obs_source_release(this->_self); - } - - this->_self = other._self; - this->_track_ownership = other._track_ownership; - - if (this->_track_ownership) { - obs_source_addref(this->_self); - } - -#ifdef auto_signal_c -#undef auto_signal_c -#endif -#define auto_signal_c(SIGNAL) this->events.SIGNAL = other.events.SIGNAL - auto_signal_c(destroy); - auto_signal_c(remove); - auto_signal_c(save); - auto_signal_c(load); - auto_signal_c(activate); - auto_signal_c(deactivate); - auto_signal_c(show); - auto_signal_c(hide); - auto_signal_c(mute); - auto_signal_c(push_to_mute_changed); - auto_signal_c(push_to_mute_delay); - auto_signal_c(push_to_talk_changed); - auto_signal_c(push_to_talk_delay); - auto_signal_c(enable); - auto_signal_c(rename); - auto_signal_c(volume); - auto_signal_c(update_properties); - auto_signal_c(update_flags); - auto_signal_c(audio_sync); - auto_signal_c(audio_mixers); - auto_signal_c(audio); - auto_signal_c(filter_add); - auto_signal_c(filter_remove); - auto_signal_c(reorder_filters); - auto_signal_c(transition_start); - auto_signal_c(transition_video_stop); - auto_signal_c(transition_stop); -#undef auto_signal_c - - return *this; -} -*/ - -streamfx::obs::deprecated_source::deprecated_source(deprecated_source&& other) - : _self(std::move(other._self)), _track_ownership(std::move(other._track_ownership)) -{ - // Clean out other source - other._self = nullptr; - other._track_ownership = false; - -#ifdef auto_signal_c -#undef auto_signal_c -#endif -#define auto_signal_c(SIGNAL) this->events.SIGNAL = std::move(other.events.SIGNAL) - auto_signal_c(destroy); - auto_signal_c(remove); - auto_signal_c(save); - auto_signal_c(load); - auto_signal_c(activate); - auto_signal_c(deactivate); - auto_signal_c(show); - auto_signal_c(hide); - auto_signal_c(mute); - auto_signal_c(push_to_mute_changed); - auto_signal_c(push_to_mute_delay); - auto_signal_c(push_to_talk_changed); - auto_signal_c(push_to_talk_delay); - auto_signal_c(enable); - auto_signal_c(rename); - auto_signal_c(volume); - auto_signal_c(update_properties); - auto_signal_c(update_flags); - auto_signal_c(audio_sync); - auto_signal_c(audio_mixers); - auto_signal_c(audio); - auto_signal_c(filter_add); - auto_signal_c(filter_remove); - auto_signal_c(reorder_filters); - auto_signal_c(transition_start); - auto_signal_c(transition_video_stop); - auto_signal_c(transition_stop); -#undef auto_signal_c -} - -streamfx::obs::deprecated_source& streamfx::obs::deprecated_source::operator=(deprecated_source&& other) -{ - if (this != &other) { - return *this; - } - - // Release previous source. - if (this->_self && this->_track_ownership) { - obs_source_release(this->_self); - } - - this->_self = std::move(other._self); - this->_track_ownership = std::move(other._track_ownership); - other._self = nullptr; - other._track_ownership = false; - -#ifdef auto_signal_c -#undef auto_signal_c -#endif -#define auto_signal_c(SIGNAL) this->events.SIGNAL = std::move(other.events.SIGNAL) - auto_signal_c(destroy); - auto_signal_c(remove); - auto_signal_c(save); - auto_signal_c(load); - auto_signal_c(activate); - auto_signal_c(deactivate); - auto_signal_c(show); - auto_signal_c(hide); - auto_signal_c(mute); - auto_signal_c(push_to_mute_changed); - auto_signal_c(push_to_mute_delay); - auto_signal_c(push_to_talk_changed); - auto_signal_c(push_to_talk_delay); - auto_signal_c(enable); - auto_signal_c(rename); - auto_signal_c(volume); - auto_signal_c(update_properties); - auto_signal_c(update_flags); - auto_signal_c(audio_sync); - auto_signal_c(audio_mixers); - auto_signal_c(audio); - auto_signal_c(filter_add); - auto_signal_c(filter_remove); - auto_signal_c(reorder_filters); - auto_signal_c(transition_start); - auto_signal_c(transition_video_stop); - auto_signal_c(transition_stop); -#undef auto_signal_c - - return *this; -} - -obs_source_type streamfx::obs::deprecated_source::type() -{ - if (!_self) { - return static_cast(-1); - } - return obs_source_get_type(_self); -} - -void* streamfx::obs::deprecated_source::type_data() -{ - if (!_self) { - return nullptr; - } - return obs_source_get_type_data(_self); -} - -uint32_t streamfx::obs::deprecated_source::width() -{ - if (!_self) { - return 0; - } - return obs_source_get_width(_self); -} - -uint32_t streamfx::obs::deprecated_source::height() -{ - if (!_self) { - return 0; - } - return obs_source_get_height(_self); -} - -bool streamfx::obs::deprecated_source::destroyed() -{ - return _self == nullptr; -} - -void streamfx::obs::deprecated_source::clear() -{ - _self = nullptr; -} - -obs_source_t* streamfx::obs::deprecated_source::get() -{ - return _self; -} diff --git a/source/obs/obs-source.hpp b/source/obs/obs-source.hpp index 4e461eb5..e2916894 100644 --- a/source/obs/obs-source.hpp +++ b/source/obs/obs-source.hpp @@ -19,119 +19,649 @@ #pragma once #include "common.hpp" -#include "util/util-event.hpp" namespace streamfx::obs { - class deprecated_source { - obs_source_t* _self; - bool _track_ownership = false; - - static void handle_destroy(void* p, calldata_t* calldata) noexcept; - static void handle_remove(void* p, calldata_t* calldata) noexcept; - static void handle_save(void* p, calldata_t* calldata) noexcept; - static void handle_load(void* p, calldata_t* calldata) noexcept; - static void handle_activate(void* p, calldata_t* calldata) noexcept; - static void handle_deactivate(void* p, calldata_t* calldata) noexcept; - static void handle_show(void* p, calldata_t* calldata) noexcept; - static void handle_hide(void* p, calldata_t* calldata) noexcept; - static void handle_enable(void* p, calldata_t* calldata) noexcept; - static void handle_push_to_mute_changed(void* p, calldata_t* calldata) noexcept; - static void handle_push_to_mute_delay(void* p, calldata_t* calldata) noexcept; - static void handle_push_to_talk_changed(void* p, calldata_t* calldata) noexcept; - static void handle_push_to_talk_delay(void* p, calldata_t* calldata) noexcept; - static void handle_rename(void* p, calldata_t* calldata) noexcept; - static void handle_update_properties(void* p, calldata_t* calldata) noexcept; - static void handle_update_flags(void* p, calldata_t* calldata) noexcept; - static void handle_mute(void* p, calldata_t* calldata) noexcept; - static void handle_volume(void* p, calldata_t* calldata) noexcept; - static void handle_audio_sync(void* p, calldata_t* calldata) noexcept; - static void handle_audio_mixers(void* p, calldata_t* calldata) noexcept; - static void handle_audio_data(void* p, obs_source_t* source, const audio_data* audio, bool muted) noexcept; - static void handle_filter_add(void* p, calldata_t* calldata) noexcept; - static void handle_filter_remove(void* p, calldata_t* calldata) noexcept; - static void handle_reorder_filters(void* p, calldata_t* calldata) noexcept; - static void handle_transition_start(void* p, calldata_t* calldata) noexcept; - static void handle_transition_video_stop(void* p, calldata_t* calldata) noexcept; - static void handle_transition_stop(void* p, calldata_t* calldata) noexcept; + class source { + obs_source_t* _ref; + bool _is_owner; public: - virtual ~deprecated_source(); + FORCE_INLINE ~source() + { + release(); + }; - deprecated_source(); + /** Empty/Invalid hard reference. + * + */ + FORCE_INLINE source() : _ref(nullptr), _is_owner(false){}; - deprecated_source(std::string name, bool track_ownership = true, bool add_reference = true); + /** Create a new hard reference from an existing pointer. + * + * @param source The source object to reference. + * @param add_reference Should we increment the reference counter (duplicate ownership) or leave as it is (transfer ownership)? + */ + FORCE_INLINE source(obs_source_t* source, bool duplicate_reference = false, bool take_ownership = true) + : _is_owner(take_ownership) + { + if (duplicate_reference) { + _ref = obs_source_get_ref(source); + } else { + _ref = source; + } + }; - deprecated_source(obs_source_t* source, bool track_ownership = true, bool add_reference = false); + /** Create a new hard reference for a given source by name. + * + * Attention: May fail if the name does not exactly match. + */ + FORCE_INLINE source(std::string_view name) : _is_owner(true) + { + _ref = obs_get_source_by_name(name.data()); + }; - public /*copy*/: - deprecated_source(deprecated_source const& other) = delete; - deprecated_source& operator=(deprecated_source const& other) = delete; + /** Create a new hard reference for a new source. + * + * Attention: May fail. + */ + FORCE_INLINE source(std::string_view id, std::string_view name, obs_data_t* settings, obs_data_t* hotkeys) + : _is_owner(true) + { + _ref = obs_source_create(id.data(), name.data(), settings, hotkeys); + if (!_ref) { + throw std::runtime_error("Failed to create source with given parameters."); + } + }; - public /*move*/: - deprecated_source(deprecated_source&& other); - deprecated_source& operator=(deprecated_source&& other); + /** Create a new hard reference for a new private source. + * + * Attention: May fail. + */ + FORCE_INLINE source(std::string_view id, std::string_view name, obs_data_t* settings) : _is_owner(true) + { + _ref = obs_source_create_private(id.data(), name.data(), settings); + if (!_ref) { + throw std::runtime_error("Failed to create source with given parameters."); + } + }; + + FORCE_INLINE source(source&& move) noexcept + { + _ref = move._ref; + _is_owner = move._is_owner; + move._ref = nullptr; + }; + + FORCE_INLINE ::streamfx::obs::source& operator=(source&& move) noexcept + { + release(); + _ref = move._ref; + _is_owner = move._is_owner; + move._ref = nullptr; + return *this; + }; + + FORCE_INLINE source(const source& copy) + { + if (copy._is_owner) { + _ref = obs_source_get_ref(copy._ref); + } else { + _ref = copy._ref; + } + _is_owner = copy._is_owner; + }; + + FORCE_INLINE ::streamfx::obs::source& operator=(const source& copy) + { + release(); + if (copy._is_owner) { + _ref = obs_source_get_ref(copy._ref); + } else { + _ref = copy._ref; + } + _is_owner = copy._is_owner; + return *this; + }; public: - obs_source_type type(); + /** Retrieve the underlying pointer for manual manipulation. + * + * Attention: Ownership remains with the class instance. + */ + FORCE_INLINE obs_source_t* get() const + { + return _ref; + }; - void* type_data(); + /** Release the underlying pointer. + * + * Useful if you need to respond to the "source_remove" or "remove" signals. + * + * EXPORT void obs_source_release(obs_source_t *source); + */ + FORCE_INLINE void release() + { + if (_ref && _is_owner) { + obs_source_release(_ref); + _ref = nullptr; + _is_owner = false; + } + }; - uint32_t width(); - uint32_t height(); + /** Duplicate the source if possible. + * + * Will create a duplicate the source entirely unless forbidden. If forbidden, will instead just return a reference. + * + * EXPORT obs_source_t *obs_source_duplicate(obs_source_t *source, const char *desired_name, bool create_private); + */ + FORCE_INLINE ::streamfx::obs::source duplicate(std::string_view name, bool is_private) + { + return obs_source_duplicate(_ref, name.data(), is_private); + }; - bool destroyed(); + public: + /** Get the source info identifier for this reference. + * + * May have a version appended to the end. + * + * EXPORT const char *obs_source_get_id(const obs_source_t *source); + */ + FORCE_INLINE std::string_view id() const + { + return obs_source_get_id(_ref); + }; - public: // Unsafe Methods - void clear(); + /** Get the source info identifier for this reference. + * + * EXPORT const char *obs_source_get_unversioned_id(const obs_source_t *source); + */ + FORCE_INLINE std::string_view unversioned_id() const + { + return obs_source_get_unversioned_id(_ref); + }; - obs_source_t* get(); + /** What type is this source? + * + */ + FORCE_INLINE obs_source_type type() const + { + return obs_source_get_type(_ref); + }; - public: // Events - struct { - // Destroy and Remove - streamfx::util::event destroy; - streamfx::util::event remove; + /** Get the output flags. + * + * EXPORT uint32_t obs_source_get_output_flags(const obs_source_t *source); + */ + FORCE_INLINE uint32_t output_flags() const + { + return obs_source_get_output_flags(_ref); + }; - // Saving, Loading and Update - streamfx::util::event save; - streamfx::util::event load; - streamfx::util::event update_properties; + /** Get the flags + * + * EXPORT uint32_t obs_source_get_flags(const obs_source_t *source); + */ + FORCE_INLINE uint32_t flags() const + { + return obs_source_get_flags(_ref); + }; - // Activate, Deactivate - streamfx::util::event activate; - streamfx::util::event deactivate; + /** Set the flags + * + * EXPORT void obs_source_set_default_flags(obs_source_t* source, uint32_t flags); + */ + FORCE_INLINE void default_flags(uint32_t flags) + { + obs_source_set_default_flags(_ref, flags); + }; - // Show Hide - streamfx::util::event show; - streamfx::util::event hide; + /** Set the flags + * + * EXPORT void obs_source_set_flags(obs_source_t *source, uint32_t flags); + */ + FORCE_INLINE void flags(uint32_t flags) + { + obs_source_set_flags(_ref, flags); + }; - // Other - streamfx::util::event enable; - streamfx::util::event rename; - streamfx::util::event update_flags; + /** What is the source type called? + * + * EXPORT const char *obs_source_get_display_name(const char *id); + */ + FORCE_INLINE std::string_view display_name() const + { + return obs_source_get_display_name(id().data()); + }; - // Hotkeys (PtM, PtT) - streamfx::util::event push_to_mute_changed; - streamfx::util::event push_to_mute_delay; - streamfx::util::event push_to_talk_changed; - streamfx::util::event push_to_talk_delay; + /** What is this source called? + * + * EXPORT const char *obs_source_get_name(const obs_source_t *source); + */ + FORCE_INLINE std::string_view name() const + { + return obs_source_get_name(_ref); + }; - // Audio - streamfx::util::event mute; - streamfx::util::event volume; - streamfx::util::event audio_sync; - streamfx::util::event audio_mixers; - streamfx::util::event audio; + /** Change the name of the source. + * + * Triggers 'rename' on the source itself, as well as 'source_rename' globally if not private. + * + * EXPORT void obs_source_set_name(obs_source_t *source, const char *name); + */ + FORCE_INLINE void name(std::string_view new_name) + { + obs_source_set_name(_ref, new_name.data()); + }; - // Filters - streamfx::util::event filter_add; - streamfx::util::event filter_remove; - streamfx::util::event reorder_filters; + /** + * + * EXPORT bool obs_source_enabled(const obs_source_t *source); + */ + FORCE_INLINE bool enabled() const + { + return obs_source_enabled(_ref); + }; - // Transition - streamfx::util::event transition_start; - streamfx::util::event transition_video_stop; - streamfx::util::event transition_stop; - } events; + /** + * + * EXPORT void obs_source_set_enabled(obs_source_t *source, bool enabled); + */ + FORCE_INLINE void enabled(bool enabled) + { + obs_source_set_enabled(_ref, enabled); + }; + + /** + * + * EXPORT bool obs_source_is_hidden(obs_source_t *source); + */ + FORCE_INLINE bool hidden() const + { + return obs_source_is_hidden(_ref); + }; + + /** + * + * EXPORT void obs_source_set_hidden(obs_source_t *source, bool hidden); + */ + FORCE_INLINE void hidden(bool v) + { + obs_source_set_hidden(_ref, v); + }; + + public /* Size */: + /** Get the base width of the source, if supported. + * + * This will be the size without any other scaling factors applied. + * + * EXPORT uint32_t obs_source_get_base_width(obs_source_t *source); + */ + FORCE_INLINE uint32_t base_width() const + { + return obs_source_get_base_width(_ref); + }; + + /** Get the base height of the source, if supported. + * + * This will be the size without any other scaling factors applied. + * + * EXPORT uint32_t obs_source_get_base_height(obs_source_t *source); + */ + FORCE_INLINE uint32_t base_height() const + { + return obs_source_get_base_height(_ref); + }; + + /** Get the reported width of the source, if supported. + * + * EXPORT uint32_t obs_source_get_width(obs_source_t *source); + */ + FORCE_INLINE uint32_t width() const + { + return obs_source_get_width(_ref); + }; + + /** Get the reported height of the source, if supported. + * + * EXPORT uint32_t obs_source_get_height(obs_source_t *source); + */ + FORCE_INLINE uint32_t height() const + { + return obs_source_get_height(_ref); + }; + + /** Get the reported size of the source, if supported. + * + * EXPORT uint32_t obs_source_get_width(obs_source_t *source); + * EXPORT uint32_t obs_source_get_height(obs_source_t *source); + */ + FORCE_INLINE std::pair size() const + { + return {width(), height()}; + }; + + public /* Configuration */: + /** Is the source configurable? + * + * EXPORT bool obs_source_configurable(const obs_source_t *source); + */ + FORCE_INLINE bool configurable() + { + return obs_source_configurable(_ref); + }; + + /** Retrieve the properties for the source. + * + * EXPORT obs_properties_t *obs_get_source_properties(const char *id); + */ + FORCE_INLINE obs_properties_t* properties() + { + return obs_source_properties(_ref); + }; + + /** Signal for properties to be updated. + * + * EXPORT void obs_source_update_properties(obs_source_t *source); + */ + FORCE_INLINE void update_properties() + { + obs_source_update_properties(_ref); + }; + + /** Retrieve the default values for the settings. + * + * EXPORT obs_data_t *obs_get_source_defaults(const char *id); + */ + FORCE_INLINE obs_data_t* defaults() + { + return obs_get_source_defaults(id().data()); + }; + + /** Retrieve the private settings. + * + * EXPORT obs_data_t *obs_source_get_private_settings(obs_source_t *item); + */ + FORCE_INLINE obs_data_t* private_settings() + { + return obs_source_get_private_settings(_ref); + }; + + /** Retrieve the current settings. + * + * EXPORT obs_data_t *obs_source_get_settings(const obs_source_t *source); + */ + FORCE_INLINE obs_data_t* settings() + { + return obs_source_get_settings(_ref); + }; + + /** Update the settings with new ones. + * + * Does not remove previously existing entries. + * + * EXPORT void obs_source_update(obs_source_t *source, obs_data_t *settings); + */ + FORCE_INLINE void update(obs_data_t* settings) + { + obs_source_update(_ref, settings); + }; + + /** Reset the settings, then update with new settings. + * + * EXPORT void obs_source_reset_settings(obs_source_t *source, obs_data_t *settings); + */ + FORCE_INLINE void reset_settings(obs_data_t* settings = nullptr) + { + obs_source_reset_settings(_ref, settings); + }; + + /** Signal the source to load. + * + * EXPORT void obs_source_load(obs_source_t *source); + */ + FORCE_INLINE void load() + { + obs_source_load(_ref); + }; + + /** Signal the source and all its filters to load. + * + * EXPORT void obs_source_load2(obs_source_t *source); + */ + FORCE_INLINE void load2() + { + obs_source_load2(_ref); + }; + + /** Signal the source to save. + * + * EXPORT void obs_source_save(obs_source_t *source); + */ + FORCE_INLINE void save() + { + obs_source_save(_ref); + }; + + public /* Interaction */: + /** + * + * EXPORT void obs_source_send_mouse_click(obs_source_t *source, const struct obs_mouse_event *event, int32_t type, bool mouse_up, uint32_t click_count); + */ + FORCE_INLINE void send_mouse_press(const obs_mouse_event* event, int32_t type, bool released, uint32_t count) + { + return obs_source_send_mouse_click(_ref, event, type, released, count); + }; + + /** + * + * EXPORT void obs_source_send_mouse_move(obs_source_t *source, const struct obs_mouse_event *event, bool mouse_leave); + */ + FORCE_INLINE void send_mouse_move(const obs_mouse_event* event, bool leave) + { + return obs_source_send_mouse_move(_ref, event, leave); + }; + + /** + * + * EXPORT void obs_source_send_mouse_wheel(obs_source_t *source, const struct obs_mouse_event *event, int x_delta, int y_delta); + */ + FORCE_INLINE void send_mouse_wheel(const obs_mouse_event* event, int32_t x_delta, int32_t y_delta) + { + return obs_source_send_mouse_wheel(_ref, event, x_delta, y_delta); + }; + + /** + * + * EXPORT void obs_source_send_key_click(obs_source_t *source, const struct obs_key_event *event, bool key_up); + */ + FORCE_INLINE void send_key_press(const obs_key_event* event, bool released) + { + return obs_source_send_key_click(_ref, event, released); + }; + + /** + * + * EXPORT void obs_source_send_focus(obs_source_t *source, bool focus); + */ + FORCE_INLINE void send_focus(bool in_focus) + { + return obs_source_send_focus(_ref, in_focus); + }; + + public /* Filters */: + /** + * + * EXPORT void obs_source_filter_add(obs_source_t *source, obs_source_t *filter); + */ + FORCE_INLINE void add_filter(::streamfx::obs::source& filter) + { + return obs_source_filter_add(_ref, filter.get()); + }; + + /** + * + * EXPORT void obs_source_filter_remove(obs_source_t *source, obs_source_t *filter); + */ + FORCE_INLINE void remove_filter(::streamfx::obs::source& filter) + { + return obs_source_filter_remove(_ref, filter.get()); + }; + + /** + * + * EXPORT obs_source_t *obs_filter_get_parent(const obs_source_t *filter); + */ + FORCE_INLINE ::streamfx::obs::source get_filter_parent() + { + return obs_filter_get_parent(_ref); + }; + + /** + * + * EXPORT obs_source_t *obs_filter_get_target(const obs_source_t *filter); + */ + FORCE_INLINE ::streamfx::obs::source get_filter_target() + { + return obs_filter_get_target(_ref); + }; + + /** + * + * EXPORT void obs_source_skip_video_filter(obs_source_t *filter); + */ + FORCE_INLINE void skip_video_filter() + { + return obs_source_skip_video_filter(_ref); + }; + + /** + * + * EXPORT bool obs_source_process_filter_begin(obs_source_t *filter, enum gs_color_format format, enum obs_allow_direct_render allow_direct); + */ + FORCE_INLINE bool process_filter_begin(gs_color_format format, obs_allow_direct_render allow_direct) + { + return obs_source_process_filter_begin(_ref, format, allow_direct); + }; + + /** + * + * EXPORT void obs_source_process_filter_end(obs_source_t *filter, gs_effect_t *effect, uint32_t width, uint32_t height); + */ + FORCE_INLINE void process_filter_end(gs_effect_t* effect, uint32_t width, uint32_t height) + { + obs_source_process_filter_end(_ref, effect, width, height); + }; + + /** + * + * EXPORT void obs_source_process_filter_tech_end(obs_source_t *filter, gs_effect_t *effect, uint32_t width, uint32_t height, const char *tech_name); + */ + FORCE_INLINE void process_filter_tech_end(gs_effect_t* effect, uint32_t width, uint32_t height, + std::string_view tech_name) + { + obs_source_process_filter_tech_end(_ref, effect, width, height, tech_name.data()); + }; + + public /* Active/Showing References */: + /** Is the source visible in main view? + * + * EXPORT bool obs_source_active(const obs_source_t *source); + */ + FORCE_INLINE bool active() const + { + return obs_source_active(_ref); + } + + /** Add a active reference (visible in main view). + * + * EXPORT void obs_source_inc_active(obs_source_t *source); + */ + FORCE_INLINE void increment_active() + { + obs_source_inc_active(_ref); + } + + /** Remove a active reference (visible in main view). + * + * EXPORT void obs_source_dec_active(obs_source_t *source); + */ + FORCE_INLINE void decrement_active() + { + obs_source_dec_active(_ref); + } + + /** Is the source visible in auxiliary views? + * + * EXPORT bool obs_source_showing(const obs_source_t *source); + */ + FORCE_INLINE bool showing() const + { + return obs_source_showing(_ref); + } + + /** Add a showing reference (visible in auxiliary view). + * + * EXPORT void obs_source_inc_showing(obs_source_t *source); + * EXPORT void obs_source_dec_showing(obs_source_t *source); + */ + FORCE_INLINE void increment_showing() + { + obs_source_inc_showing(_ref); + } + + /** Add a showing reference (visible in auxiliary view). + * + * EXPORT void obs_source_inc_showing(obs_source_t *source); + * EXPORT void obs_source_dec_showing(obs_source_t *source); + */ + FORCE_INLINE void decrement_showing() + { + obs_source_dec_showing(_ref); + } + + public /* ToDo */: + + /** + * + * EXPORT obs_missing_files_t* obs_source_get_missing_files(const obs_source_t *source); + */ + obs_missing_files_t* get_missing_files(); + + /** + * + * EXPORT void obs_source_replace_missing_file(obs_missing_file_cb cb, obs_source_t *source, const char *new_path, void *data); + */ + void replace_missing_file(obs_missing_file_cb cb, std::string_view path, void* data); + + public: + FORCE_INLINE operator obs_source_t*() const + { + return _ref; + } + + FORCE_INLINE obs_source_t* operator*() const + { + return _ref; + } + + FORCE_INLINE operator bool() const + { + return _ref != nullptr; + }; + + FORCE_INLINE bool operator==(source const& rhs) const + { + return _ref == rhs._ref; + }; + + FORCE_INLINE bool operator<(source const& rhs) const + { + return _ref < rhs._ref; + }; + + FORCE_INLINE bool operator==(obs_source_t* const& rhs) const + { + return _ref == rhs; + }; }; } // namespace streamfx::obs diff --git a/source/obs/obs-weak-source.cpp b/source/obs/obs-weak-source.cpp new file mode 100644 index 00000000..1d6301ef --- /dev/null +++ b/source/obs/obs-weak-source.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2022 Michael Fabian Dirks + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "obs-weak-source.hpp" diff --git a/source/obs/obs-weak-source.hpp b/source/obs/obs-weak-source.hpp new file mode 100644 index 00000000..da34790f --- /dev/null +++ b/source/obs/obs-weak-source.hpp @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2022 Michael Fabian Dirks + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include "common.hpp" +#include "obs-source.hpp" + +namespace streamfx::obs { + class source; + + class weak_source { + obs_weak_source_t* _ref; + + public: + ~weak_source() + { + if (_ref) { + obs_weak_source_release(_ref); + } + }; + + /** Empty/Invalid weak reference. + * + */ + weak_source() : _ref(nullptr){}; + + /** Create a new weak reference from an existing pointer. + * + * Attention: Ownership of obs_weak_source_t is transferred to the class itself, and should not be released. + */ + weak_source(obs_weak_source_t* source) : _ref(source) + { + if (!_ref) + throw std::invalid_argument("Parameter 'source' does not define a valid source."); + }; + + /** Create a new weak reference from an existing hard reference. + */ + weak_source(obs_source_t* source) + { + _ref = obs_source_get_weak_source(source); + if (!_ref) + throw std::invalid_argument("Parameter 'source' does not define a valid source."); + }; + + /** Create a new weak reference from an existing hard reference. + */ + weak_source(::streamfx::obs::source& source) + { + _ref = obs_source_get_weak_source(source.get()); + if (!_ref) + throw std::invalid_argument("Parameter 'source' does not define a valid source."); + }; + + /** Create a new weak reference for a given source by name. + * + * Attention: May fail if the name does not exactly match. + */ + weak_source(std::string_view name) + { + std::shared_ptr ref{obs_get_source_by_name(name.data()), + [](obs_source_t* v) { obs_source_release(v); }}; + if (!ref) { + throw std::invalid_argument("Parameter 'name' does not define an valid source."); + } + _ref = obs_source_get_weak_source(ref.get()); + }; + + weak_source(weak_source&& move) noexcept + { + _ref = move._ref; + move._ref = nullptr; + }; + + FORCE_INLINE ::streamfx::obs::weak_source& operator=(weak_source&& move) noexcept + { + if (_ref) { + obs_weak_source_release(_ref); + _ref = nullptr; + } + if (move._ref) { + _ref = move._ref; + move._ref = nullptr; + } + return *this; + }; + + weak_source(const weak_source& copy) + { + _ref = copy._ref; + obs_weak_source_addref(_ref); + }; + + FORCE_INLINE ::streamfx::obs::weak_source& operator=(const weak_source& copy) + { + if (_ref) { + obs_weak_source_release(_ref); + _ref = nullptr; + } + if (copy._ref) { + _ref = copy._ref; + obs_weak_source_addref(_ref); + } + + return *this; + }; + + /** Retrieve the underlying pointer for manual manipulation. + * + * Attention: Ownership remains with the class instance. + */ + FORCE_INLINE obs_weak_source_t* get() const + { + return _ref; + }; + + /** Is the weak reference expired? + * + * A weak reference is expired when the original object it is pointing at no longer exists. + */ + FORCE_INLINE bool expired() const + { + return (!_ref) || (obs_weak_source_expired(_ref)); + }; + + /** Try and acquire a hard reference to the source. + * + * May fail if the reference expired before we successfully acquire it. + */ + FORCE_INLINE ::streamfx::obs::source lock() const + { + return {obs_weak_source_get_source(_ref)}; + }; + + public: + FORCE_INLINE operator obs_weak_source_t*() const + { + return _ref; + } + + FORCE_INLINE obs_weak_source_t* operator*() const + { + return _ref; + } + + FORCE_INLINE operator bool() const + { + return !expired(); + }; + + FORCE_INLINE bool operator==(weak_source const& rhs) const + { + return _ref == rhs._ref; + }; + + FORCE_INLINE bool operator<(weak_source const& rhs) const + { + return _ref < rhs._ref; + }; + + FORCE_INLINE bool operator==(obs_weak_source_t* const& rhs) const + { + return _ref == rhs; + }; + + FORCE_INLINE bool operator==(source const& rhs) const + { + return obs_weak_source_references_source(_ref, rhs.get()); + }; + + FORCE_INLINE bool operator==(obs_source_t* const& rhs) const + { + return obs_weak_source_references_source(_ref, rhs); + }; + }; +} // namespace streamfx::obs