improve streams also throw os events

This commit is contained in:
Green Sky 2024-09-25 10:46:13 +02:00
parent 4d5d708d6d
commit d0eeef2b94
No known key found for this signature in database
6 changed files with 134 additions and 69 deletions

View File

@ -32,18 +32,5 @@ namespace Content1::Components {
entt::dense_set<Contact3> 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<File2I> open(ObjectHandle h) = 0;
};

View File

@ -274,15 +274,19 @@ DebugToxCall::~DebugToxCall(void) {
for (auto& [fid, call] : _calls) {
if (static_cast<bool>(call.incoming_vsrc)) {
_os.throwEventDestroy(call.incoming_vsrc);
call.incoming_vsrc.destroy();
}
if (static_cast<bool>(call.incoming_asrc)) {
_os.throwEventDestroy(call.incoming_asrc);
call.incoming_asrc.destroy();
}
if (static_cast<bool>(call.outgoing_vsink)) {
_os.throwEventDestroy(call.outgoing_vsink);
call.outgoing_vsink.destroy();
}
if (static_cast<bool>(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<ToxAVCallVideoSink>(_toxav, fid);
call.outgoing_vsink.emplace<ToxAVCallVideoSink*>(new_vsink.get());
call.outgoing_vsink.emplace<Components::FrameStream2Sink<SDLVideoFrame>>(std::move(new_vsink));
call.outgoing_vsink.emplace<Components::StreamSink>("ToxAV friend call video", std::string{entt::type_name<SDLVideoFrame>::value()});
call.outgoing_vsink.emplace<Components::StreamSink>(Components::StreamSink::create<SDLVideoFrame>("ToxAV friend call video"));
_os.throwEventConstruct(call.outgoing_vsink);
}
call.outgoing_asink = {_os.registry(), _os.registry().create()};
{
auto new_asink = std::make_unique<ToxAVCallAudioSink>(_toxav, fid);
call.outgoing_asink.emplace<ToxAVCallAudioSink*>(new_asink.get());
call.outgoing_asink.emplace<Components::FrameStream2Sink<AudioFrame>>(std::move(new_asink));
call.outgoing_asink.emplace<Components::StreamSink>("ToxAV friend call audio", std::string{entt::type_name<AudioFrame>::value()});
call.outgoing_asink.emplace<Components::StreamSink>(Components::StreamSink::create<AudioFrame>("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<SDLVideoFrameStream2MultiSource>();
call.incoming_vsrc.emplace<SDLVideoFrameStream2MultiSource*>(new_vsrc.get());
call.incoming_vsrc.emplace<Components::FrameStream2Source<SDLVideoFrame>>(std::move(new_vsrc));
call.incoming_vsrc.emplace<Components::StreamSource>("ToxAV friend call video", std::string{entt::type_name<SDLVideoFrame>::value()});
call.incoming_vsrc.emplace<Components::StreamSource>(Components::StreamSource::create<SDLVideoFrame>("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<AudioFrameStream2MultiSource>();
call.incoming_asrc.emplace<AudioFrameStream2MultiSource*>(new_asrc.get());
call.incoming_asrc.emplace<Components::FrameStream2Source<AudioFrame>>(std::move(new_asrc));
call.incoming_asrc.emplace<Components::StreamSource>("ToxAV friend call audio", std::string{entt::type_name<AudioFrame>::value()});
call.incoming_asrc.emplace<Components::StreamSource>(Components::StreamSource::create<AudioFrame>("ToxAV friend call audio"));
_os.throwEventConstruct(call.incoming_asrc);
}
}
}
@ -418,15 +426,19 @@ float DebugToxCall::render(void) {
// TODO: stream manager disconnectAll()
if (static_cast<bool>(call.incoming_vsrc)) {
_os.throwEventDestroy(call.incoming_vsrc);
call.incoming_vsrc.destroy();
}
if (static_cast<bool>(call.incoming_asrc)) {
_os.throwEventDestroy(call.incoming_asrc);
call.incoming_asrc.destroy();
}
if (static_cast<bool>(call.outgoing_vsink)) {
_os.throwEventDestroy(call.outgoing_vsink);
call.outgoing_vsink.destroy();
}
if (static_cast<bool>(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<bool>(call.incoming_vsrc)) {
_os.throwEventDestroy(call.incoming_vsrc);
call.incoming_vsrc.destroy();
}
if (static_cast<bool>(call.incoming_asrc)) {
_os.throwEventDestroy(call.incoming_asrc);
call.incoming_asrc.destroy();
}
if (static_cast<bool>(call.outgoing_vsink)) {
_os.throwEventDestroy(call.outgoing_vsink);
call.outgoing_vsink.destroy();
}
if (static_cast<bool>(call.outgoing_asink)) {
_os.throwEventDestroy(call.outgoing_asink);
call.outgoing_asink.destroy();
}
}

View File

@ -58,7 +58,7 @@ DebugVideoTap::DebugVideoTap(ObjectStore2& os, StreamManager& sm, TextureUploade
std::move(dvts)
);
_tap.emplace<Components::StreamSink>("DebugVideoTap", std::string{entt::type_name<SDLVideoFrame>::value()});
_tap.emplace<Components::StreamSink>(Components::StreamSink::create<SDLVideoFrame>("DebugVideoTap"));
} catch (...) {
_os.registry().destroy(_tap);
}

View File

@ -154,7 +154,9 @@ MainScreen::MainScreen(SimpleConfigModel&& conf_, SDL_Renderer* renderer_, Theme
std::make_unique<SDLVideoCameraContent>()
);
vsrc.emplace<Components::StreamSource>("WebCam", std::string{entt::type_name<SDLVideoFrame>::value()});
vsrc.emplace<Components::StreamSource>(Components::StreamSource::create<SDLVideoFrame>("WebCam"));
os.throwEventConstruct(vsrc);
} catch (...) {
os.registry().destroy(vsrc);
}
@ -176,7 +178,9 @@ MainScreen::MainScreen(SimpleConfigModel&& conf_, SDL_Renderer* renderer_, Theme
std::make_unique<SDLAudioOutputDeviceDefaultSink>()
);
asink.emplace<Components::StreamSink>("LoudSpeaker", std::string{entt::type_name<AudioFrame>::value()});
asink.emplace<Components::StreamSink>(Components::StreamSink::create<AudioFrame>("LoudSpeaker"));
os.throwEventConstruct(asink);
} catch (...) {
os.registry().destroy(asink);
}

View File

@ -13,17 +13,26 @@
#include <thread>
#include <chrono>
// fwd
class StreamManager;
namespace Components {
struct StreamSource {
std::string name;
std::string frame_type_name;
// TODO: connect fn
std::function<bool(StreamManager&, Object, Object, bool)> connect_fn;
template<typename FrameType>
static StreamSource create(const std::string& name);
};
struct StreamSink {
std::string name;
std::string frame_type_name;
// TODO: connect fn
template<typename FrameType>
static StreamSink create(const std::string& name);
};
template<typename FrameType>
@ -102,8 +111,6 @@ class StreamManager {
}
}
// TODO: default typed sources and sinks
// stream type is FrameStream2I<FrameType>
// TODO: improve this design
// src and sink need to be a FrameStream2MultiStream<FrameType>
@ -135,14 +142,6 @@ class StreamManager {
return false;
}
// HACK:
if (!h_src.all_of<Components::StreamSource>()) {
h_src.emplace<Components::StreamSource>("", std::string{entt::type_name<FrameType>::value()});
}
if (!h_sink.all_of<Components::StreamSink>()) {
h_sink.emplace<Components::StreamSink>("", std::string{entt::type_name<FrameType>::value()});
}
auto& src_stream = h_src.get<Components::FrameStream2Source<FrameType>>();
auto& sink_stream = h_sink.get<Components::FrameStream2Sink<FrameType>>();
@ -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<bool>(h_src) || !static_cast<bool>(h_sink)) {
// an object does not exist
return false;
}
// get src and sink comps
if (!h_src.all_of<Components::StreamSource>()) {
// src not stream source
return false;
}
if (!h_sink.all_of<Components::StreamSink>()) {
// sink not stream sink
return false;
}
const auto& ssrc = h_src.get<Components::StreamSource>();
const auto& ssink = h_sink.get<Components::StreamSink>();
// compare type
if (ssrc.frame_type_name != ssink.frame_type_name) {
return false;
}
// always fail in debug mode
assert(static_cast<bool>(ssrc.connect_fn));
if (!static_cast<bool>(ssrc.connect_fn)) {
return false;
}
// use connect fn from src
return ssrc.connect_fn(*this, src, sink, threaded);
}
template<typename StreamType>
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<typename FrameType>
StreamSource StreamSource::create(const std::string& name) {
return StreamSource{
name,
std::string{entt::type_name<FrameType>::value()},
+[](StreamManager& sm, Object src, Object sink, bool threaded) {
return sm.connect<FrameType>(src, sink, threaded);
},
};
}
template<typename FrameType>
StreamSink StreamSink::create(const std::string& name) {
return StreamSink{
name,
std::string{entt::type_name<FrameType>::value()},
};
}
} // Components

View File

@ -1,8 +1,5 @@
#include "./stream_manager_ui.hpp"
#include "./content/sdl_video_frame_stream2.hpp"
#include "./content/audio_stream.hpp"
#include <solanaceae/object_store/object_store.hpp>
#include <imgui/imgui.h>
@ -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<Components::StreamSink>().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<Components::StreamSink>().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<SDLVideoFrame>::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<Components::StreamSource>().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<SDLVideoFrame>(oc_src, oc);
}
ImGui::PopID();
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("connect audio", ss.frame_type_name == entt::type_name<AudioFrame>::value())) {
for (const auto& [oc_src, s_src] : _os.registry().view<Components::StreamSource>().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<AudioFrame>(oc_src, oc);
_sm.connect(oc_src, oc);
}
ImGui::PopID();