diff --git a/src/content/content.hpp b/src/content/content.hpp index 75925bb..e763592 100644 --- a/src/content/content.hpp +++ b/src/content/content.hpp @@ -32,18 +32,5 @@ namespace Content1::Components { entt::dense_set participants; }; - struct ReadHeadHint { - // points to the first byte we want - // this is just a hint, that can be set from outside - // to guide the sequential "piece picker" strategy - // the strategy *should* set this to the first byte we dont yet have - uint64_t offset_into_file {0u}; - }; - } // Content::Components -// TODO: i have no idea -struct RawFile2ReadFromContentFactoryI { - virtual std::shared_ptr open(ObjectHandle h) = 0; -}; - diff --git a/src/debug_tox_call.cpp b/src/debug_tox_call.cpp index a84d20c..5a5888c 100644 --- a/src/debug_tox_call.cpp +++ b/src/debug_tox_call.cpp @@ -274,15 +274,19 @@ DebugToxCall::~DebugToxCall(void) { for (auto& [fid, call] : _calls) { if (static_cast(call.incoming_vsrc)) { + _os.throwEventDestroy(call.incoming_vsrc); call.incoming_vsrc.destroy(); } if (static_cast(call.incoming_asrc)) { + _os.throwEventDestroy(call.incoming_asrc); call.incoming_asrc.destroy(); } if (static_cast(call.outgoing_vsink)) { + _os.throwEventDestroy(call.outgoing_vsink); call.outgoing_vsink.destroy(); } if (static_cast(call.outgoing_asink)) { + _os.throwEventDestroy(call.outgoing_asink); call.outgoing_asink.destroy(); } } @@ -375,14 +379,16 @@ float DebugToxCall::render(void) { auto new_vsink = std::make_unique(_toxav, fid); call.outgoing_vsink.emplace(new_vsink.get()); call.outgoing_vsink.emplace>(std::move(new_vsink)); - call.outgoing_vsink.emplace("ToxAV friend call video", std::string{entt::type_name::value()}); + call.outgoing_vsink.emplace(Components::StreamSink::create("ToxAV friend call video")); + _os.throwEventConstruct(call.outgoing_vsink); } call.outgoing_asink = {_os.registry(), _os.registry().create()}; { auto new_asink = std::make_unique(_toxav, fid); call.outgoing_asink.emplace(new_asink.get()); call.outgoing_asink.emplace>(std::move(new_asink)); - call.outgoing_asink.emplace("ToxAV friend call audio", std::string{entt::type_name::value()}); + call.outgoing_asink.emplace(Components::StreamSink::create("ToxAV friend call audio")); + _os.throwEventConstruct(call.outgoing_asink); } // create sources @@ -392,7 +398,8 @@ float DebugToxCall::render(void) { auto new_vsrc = std::make_unique(); call.incoming_vsrc.emplace(new_vsrc.get()); call.incoming_vsrc.emplace>(std::move(new_vsrc)); - call.incoming_vsrc.emplace("ToxAV friend call video", std::string{entt::type_name::value()}); + call.incoming_vsrc.emplace(Components::StreamSource::create("ToxAV friend call video")); + _os.throwEventConstruct(call.incoming_vsrc); } } if (call.incoming_a) { @@ -401,7 +408,8 @@ float DebugToxCall::render(void) { auto new_asrc = std::make_unique(); call.incoming_asrc.emplace(new_asrc.get()); call.incoming_asrc.emplace>(std::move(new_asrc)); - call.incoming_asrc.emplace("ToxAV friend call audio", std::string{entt::type_name::value()}); + call.incoming_asrc.emplace(Components::StreamSource::create("ToxAV friend call audio")); + _os.throwEventConstruct(call.incoming_asrc); } } } @@ -418,15 +426,19 @@ float DebugToxCall::render(void) { // TODO: stream manager disconnectAll() if (static_cast(call.incoming_vsrc)) { + _os.throwEventDestroy(call.incoming_vsrc); call.incoming_vsrc.destroy(); } if (static_cast(call.incoming_asrc)) { + _os.throwEventDestroy(call.incoming_asrc); call.incoming_asrc.destroy(); } if (static_cast(call.outgoing_vsink)) { + _os.throwEventDestroy(call.outgoing_vsink); call.outgoing_vsink.destroy(); } if (static_cast(call.outgoing_asink)) { + _os.throwEventDestroy(call.outgoing_asink); call.outgoing_asink.destroy(); } } @@ -468,15 +480,19 @@ bool DebugToxCall::onEvent(const Events::FriendCallState& e) { (call.state & TOXAV_FRIEND_CALL_STATE_ERROR) != 0 ) { if (static_cast(call.incoming_vsrc)) { + _os.throwEventDestroy(call.incoming_vsrc); call.incoming_vsrc.destroy(); } if (static_cast(call.incoming_asrc)) { + _os.throwEventDestroy(call.incoming_asrc); call.incoming_asrc.destroy(); } if (static_cast(call.outgoing_vsink)) { + _os.throwEventDestroy(call.outgoing_vsink); call.outgoing_vsink.destroy(); } if (static_cast(call.outgoing_asink)) { + _os.throwEventDestroy(call.outgoing_asink); call.outgoing_asink.destroy(); } } diff --git a/src/debug_video_tap.cpp b/src/debug_video_tap.cpp index f76bdcc..1ede8a8 100644 --- a/src/debug_video_tap.cpp +++ b/src/debug_video_tap.cpp @@ -58,7 +58,7 @@ DebugVideoTap::DebugVideoTap(ObjectStore2& os, StreamManager& sm, TextureUploade std::move(dvts) ); - _tap.emplace("DebugVideoTap", std::string{entt::type_name::value()}); + _tap.emplace(Components::StreamSink::create("DebugVideoTap")); } catch (...) { _os.registry().destroy(_tap); } diff --git a/src/main_screen.cpp b/src/main_screen.cpp index e7de762..00cd09f 100644 --- a/src/main_screen.cpp +++ b/src/main_screen.cpp @@ -154,7 +154,9 @@ MainScreen::MainScreen(SimpleConfigModel&& conf_, SDL_Renderer* renderer_, Theme std::make_unique() ); - vsrc.emplace("WebCam", std::string{entt::type_name::value()}); + vsrc.emplace(Components::StreamSource::create("WebCam")); + + os.throwEventConstruct(vsrc); } catch (...) { os.registry().destroy(vsrc); } @@ -176,7 +178,9 @@ MainScreen::MainScreen(SimpleConfigModel&& conf_, SDL_Renderer* renderer_, Theme std::make_unique() ); - asink.emplace("LoudSpeaker", std::string{entt::type_name::value()}); + asink.emplace(Components::StreamSink::create("LoudSpeaker")); + + os.throwEventConstruct(asink); } catch (...) { os.registry().destroy(asink); } diff --git a/src/stream_manager.hpp b/src/stream_manager.hpp index 0dc1353..e19aa06 100644 --- a/src/stream_manager.hpp +++ b/src/stream_manager.hpp @@ -13,17 +13,26 @@ #include #include +// fwd +class StreamManager; + namespace Components { struct StreamSource { std::string name; std::string frame_type_name; - // TODO: connect fn + + std::function connect_fn; + + template + static StreamSource create(const std::string& name); }; struct StreamSink { std::string name; std::string frame_type_name; - // TODO: connect fn + + template + static StreamSink create(const std::string& name); }; template @@ -102,8 +111,6 @@ class StreamManager { } } - // TODO: default typed sources and sinks - // stream type is FrameStream2I // TODO: improve this design // src and sink need to be a FrameStream2MultiStream @@ -135,14 +142,6 @@ class StreamManager { return false; } - // HACK: - if (!h_src.all_of()) { - h_src.emplace("", std::string{entt::type_name::value()}); - } - if (!h_sink.all_of()) { - h_sink.emplace("", std::string{entt::type_name::value()}); - } - auto& src_stream = h_src.get>(); auto& sink_stream = h_sink.get>(); @@ -195,6 +194,43 @@ class StreamManager { return true; } + bool connect(Object src, Object sink, bool threaded = true) { + auto h_src = _os.objectHandle(src); + auto h_sink = _os.objectHandle(sink); + if (!static_cast(h_src) || !static_cast(h_sink)) { + // an object does not exist + return false; + } + + // get src and sink comps + if (!h_src.all_of()) { + // src not stream source + return false; + } + + if (!h_sink.all_of()) { + // sink not stream sink + return false; + } + + const auto& ssrc = h_src.get(); + const auto& ssink = h_sink.get(); + + // compare type + if (ssrc.frame_type_name != ssink.frame_type_name) { + return false; + } + + // always fail in debug mode + assert(static_cast(ssrc.connect_fn)); + if (!static_cast(ssrc.connect_fn)) { + return false; + } + + // use connect fn from src + return ssrc.connect_fn(*this, src, sink, threaded); + } + template bool disconnect(Object src, Object sink) { auto res = std::find_if( @@ -258,3 +294,27 @@ class StreamManager { } }; +namespace Components { + + // we require the complete sm type here + template + StreamSource StreamSource::create(const std::string& name) { + return StreamSource{ + name, + std::string{entt::type_name::value()}, + +[](StreamManager& sm, Object src, Object sink, bool threaded) { + return sm.connect(src, sink, threaded); + }, + }; + } + + template + StreamSink StreamSink::create(const std::string& name) { + return StreamSink{ + name, + std::string{entt::type_name::value()}, + }; + } + +} // Components + diff --git a/src/stream_manager_ui.cpp b/src/stream_manager_ui.cpp index 9b47341..57b6332 100644 --- a/src/stream_manager_ui.cpp +++ b/src/stream_manager_ui.cpp @@ -1,8 +1,5 @@ #include "./stream_manager_ui.hpp" -#include "./content/sdl_video_frame_stream2.hpp" -#include "./content/audio_stream.hpp" - #include #include @@ -42,7 +39,7 @@ void StreamManagerUI::render(void) { // by fametype ?? - if (ImGui::CollapsingHeader("Sources")) { + if (ImGui::CollapsingHeader("Sources", ImGuiTreeNodeFlags_DefaultOpen)) { // list sources if (ImGui::BeginTable("sources_and_sinks", 4, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_BordersInnerV)) { ImGui::TableSetupColumn("id"); @@ -65,7 +62,34 @@ void StreamManagerUI::render(void) { ImGui::TableNextColumn(); if (ImGui::SmallButton("->")) { - // TODO: list type sinks + ImGui::OpenPopup("src_connect"); + } + if (ImGui::BeginPopup("src_connect")) { + if (ImGui::BeginMenu("connect to")) { + for (const auto& [oc_sink, s_sink] : _os.registry().view().each()) { + if (s_sink.frame_type_name != ss.frame_type_name) { + continue; + } + + ImGui::PushID(entt::to_integral(oc_sink)); + + std::string sink_label {"src "}; + sink_label += std::to_string(entt::to_integral(entt::to_entity(oc_sink))); + sink_label += " ("; + sink_label += s_sink.name; + sink_label += ")["; + sink_label += s_sink.frame_type_name; + sink_label += "]"; + if (ImGui::MenuItem(sink_label.c_str())) { + _sm.connect(oc, oc_sink); + } + + ImGui::PopID(); + } + + ImGui::EndMenu(); + } + ImGui::EndPopup(); } ImGui::TableNextColumn(); @@ -78,7 +102,7 @@ void StreamManagerUI::render(void) { } } // sources header - if (ImGui::CollapsingHeader("Sinks")) { + if (ImGui::CollapsingHeader("Sinks", ImGuiTreeNodeFlags_DefaultOpen)) { // list sinks if (ImGui::BeginTable("sources_and_sinks", 4, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_BordersInnerV)) { ImGui::TableSetupColumn("id"); @@ -89,8 +113,6 @@ void StreamManagerUI::render(void) { ImGui::TableHeadersRow(); for (const auto& [oc, ss] : _os.registry().view().each()) { - //ImGui::Text("sink %d (%s)[%s]", entt::to_integral(entt::to_entity(oc)), ss.name.c_str(), ss.frame_type_name.c_str()); - ImGui::PushID(entt::to_integral(oc)); ImGui::TableNextColumn(); @@ -102,10 +124,11 @@ void StreamManagerUI::render(void) { ImGui::TableNextColumn(); if (ImGui::SmallButton("->")) { - // TODO: list type sinks + ImGui::OpenPopup("sink_connect"); } - if (ImGui::BeginPopupContextItem("sink_connect")) { - if (ImGui::BeginMenu("connect video", ss.frame_type_name == entt::type_name::value())) { + // ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings + if (ImGui::BeginPopup("sink_connect")) { + if (ImGui::BeginMenu("connect to")) { for (const auto& [oc_src, s_src] : _os.registry().view().each()) { if (s_src.frame_type_name != ss.frame_type_name) { continue; @@ -121,32 +144,7 @@ void StreamManagerUI::render(void) { source_label += s_src.frame_type_name; source_label += "]"; if (ImGui::MenuItem(source_label.c_str())) { - _sm.connect(oc_src, oc); - } - - ImGui::PopID(); - } - - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("connect audio", ss.frame_type_name == entt::type_name::value())) { - for (const auto& [oc_src, s_src] : _os.registry().view().each()) { - if (s_src.frame_type_name != ss.frame_type_name) { - continue; - } - - ImGui::PushID(entt::to_integral(oc_src)); - - std::string source_label {"src "}; - source_label += std::to_string(entt::to_integral(entt::to_entity(oc_src))); - source_label += " ("; - source_label += s_src.name; - source_label += ")["; - source_label += s_src.frame_type_name; - source_label += "]"; - if (ImGui::MenuItem(source_label.c_str())) { - _sm.connect(oc_src, oc); + _sm.connect(oc_src, oc); } ImGui::PopID();