mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-13 19:29:58 +01:00
Added history of recent SRT hosts
Saving known hosts in settings and validating ip and port in SRT connector for source
This commit is contained in:
@@ -35,7 +35,7 @@ std::list<std::string> splitted(const std::string& str, char delim);
|
|||||||
std::string joinned(std::list<std::string> strlist, char separator = ' ');
|
std::string joinned(std::list<std::string> strlist, char separator = ' ');
|
||||||
|
|
||||||
// returns true if the string
|
// returns true if the string
|
||||||
bool is_a_number(const std::string& str, int *val = nullptr);
|
bool is_a_number(const std::string& str, int *val);
|
||||||
|
|
||||||
// find common parts in a list of strings
|
// find common parts in a list of strings
|
||||||
std::string common_prefix(const std::list<std::string> &allStrings);
|
std::string common_prefix(const std::list<std::string> &allStrings);
|
||||||
|
|||||||
99
Settings.cpp
99
Settings.cpp
@@ -52,6 +52,22 @@ XMLElement *save_history(Settings::History &h, const char *nodename, XMLDocument
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XMLElement *save_knownhost(Settings::KnownHosts &h, const char *nodename, XMLDocument &xmlDoc)
|
||||||
|
{
|
||||||
|
XMLElement *pElement = xmlDoc.NewElement( nodename );
|
||||||
|
pElement->SetAttribute("protocol", h.protocol.c_str());
|
||||||
|
for(auto it = h.hosts.cbegin(); it != h.hosts.cend(); ++it) {
|
||||||
|
XMLElement *hostNode = xmlDoc.NewElement("host");
|
||||||
|
XMLText *text = xmlDoc.NewText( it->first.c_str() );
|
||||||
|
hostNode->InsertEndChild( text );
|
||||||
|
hostNode->SetAttribute("port", it->second.c_str());
|
||||||
|
pElement->InsertFirstChild(hostNode);
|
||||||
|
}
|
||||||
|
return pElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Settings::Save(uint64_t runtime)
|
void Settings::Save(uint64_t runtime)
|
||||||
{
|
{
|
||||||
// impose C locale for all app
|
// impose C locale for all app
|
||||||
@@ -111,8 +127,6 @@ void Settings::Save(uint64_t runtime)
|
|||||||
applicationNode->SetAttribute("pannel_history_mode", application.pannel_current_session_mode);
|
applicationNode->SetAttribute("pannel_history_mode", application.pannel_current_session_mode);
|
||||||
applicationNode->SetAttribute("stream_protocol", application.stream_protocol);
|
applicationNode->SetAttribute("stream_protocol", application.stream_protocol);
|
||||||
applicationNode->SetAttribute("broadcast_port", application.broadcast_port);
|
applicationNode->SetAttribute("broadcast_port", application.broadcast_port);
|
||||||
applicationNode->SetAttribute("custom_connect_ip", application.custom_connect_ip.c_str());
|
|
||||||
applicationNode->SetAttribute("custom_connect_port", application.custom_connect_port.c_str());
|
|
||||||
pRoot->InsertEndChild(applicationNode);
|
pRoot->InsertEndChild(applicationNode);
|
||||||
|
|
||||||
// Widgets
|
// Widgets
|
||||||
@@ -245,6 +259,17 @@ void Settings::Save(uint64_t runtime)
|
|||||||
pRoot->InsertEndChild(recent);
|
pRoot->InsertEndChild(recent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hosts known hosts
|
||||||
|
{
|
||||||
|
XMLElement *knownhosts = xmlDoc.NewElement( "Hosts" );
|
||||||
|
|
||||||
|
// recent SRT hosts
|
||||||
|
knownhosts->InsertEndChild( save_knownhost(application.recentSRT, "SRT", xmlDoc));
|
||||||
|
|
||||||
|
|
||||||
|
pRoot->InsertEndChild(knownhosts);
|
||||||
|
}
|
||||||
|
|
||||||
// Timer Metronome
|
// Timer Metronome
|
||||||
XMLElement *timerConfNode = xmlDoc.NewElement( "Timer" );
|
XMLElement *timerConfNode = xmlDoc.NewElement( "Timer" );
|
||||||
timerConfNode->SetAttribute("mode", application.timer.mode);
|
timerConfNode->SetAttribute("mode", application.timer.mode);
|
||||||
@@ -304,6 +329,33 @@ void load_history(Settings::History &h, const char *nodename, XMLElement *root)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void load_knownhost(Settings::KnownHosts &h, const char *nodename, XMLElement *root)
|
||||||
|
{
|
||||||
|
XMLElement * pElement = root->FirstChildElement(nodename);
|
||||||
|
if (pElement)
|
||||||
|
{
|
||||||
|
// list of hosts
|
||||||
|
h.hosts.clear();
|
||||||
|
XMLElement* host_ = pElement->FirstChildElement("host");
|
||||||
|
for( ; host_ ; host_ = host_->NextSiblingElement())
|
||||||
|
{
|
||||||
|
const char *ip_ = host_->GetText();
|
||||||
|
if (ip_) {
|
||||||
|
const char *port_ = host_->Attribute("port");
|
||||||
|
if (port_)
|
||||||
|
h.push( std::string(ip_), std::string(port_) );
|
||||||
|
else
|
||||||
|
h.push( std::string(ip_) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// protocol attribute
|
||||||
|
const char *protocol_ = pElement->Attribute("protocol");
|
||||||
|
if (protocol_)
|
||||||
|
h.protocol = std::string(protocol_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Settings::Load()
|
void Settings::Load()
|
||||||
{
|
{
|
||||||
// impose C locale for all app
|
// impose C locale for all app
|
||||||
@@ -346,16 +398,6 @@ void Settings::Load()
|
|||||||
applicationNode->QueryIntAttribute("pannel_history_mode", &application.pannel_current_session_mode);
|
applicationNode->QueryIntAttribute("pannel_history_mode", &application.pannel_current_session_mode);
|
||||||
applicationNode->QueryIntAttribute("stream_protocol", &application.stream_protocol);
|
applicationNode->QueryIntAttribute("stream_protocol", &application.stream_protocol);
|
||||||
applicationNode->QueryIntAttribute("broadcast_port", &application.broadcast_port);
|
applicationNode->QueryIntAttribute("broadcast_port", &application.broadcast_port);
|
||||||
const char *ip = applicationNode->Attribute("custom_connect_ip");
|
|
||||||
if (ip)
|
|
||||||
application.custom_connect_ip = std::string(ip);
|
|
||||||
else
|
|
||||||
application.custom_connect_ip = "127.0.0.1";
|
|
||||||
const char *p = applicationNode->Attribute("custom_connect_port");
|
|
||||||
if (p)
|
|
||||||
application.custom_connect_port = std::string(p);
|
|
||||||
else
|
|
||||||
application.custom_connect_port = "8888";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Widgets
|
// Widgets
|
||||||
@@ -533,6 +575,16 @@ void Settings::Load()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bloc of known hosts
|
||||||
|
{
|
||||||
|
XMLElement * pElement = pRoot->FirstChildElement("Hosts");
|
||||||
|
if (pElement)
|
||||||
|
{
|
||||||
|
// recent SRT hosts
|
||||||
|
load_knownhost(application.recentSRT, "SRT", pElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Timer Metronome
|
// Timer Metronome
|
||||||
XMLElement * timerconfnode = pRoot->FirstChildElement("Timer");
|
XMLElement * timerconfnode = pRoot->FirstChildElement("Timer");
|
||||||
if (timerconfnode != nullptr) {
|
if (timerconfnode != nullptr) {
|
||||||
@@ -595,6 +647,29 @@ void Settings::History::validate()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Settings::KnownHosts::push(const string &ip, const string &port)
|
||||||
|
{
|
||||||
|
if (!ip.empty()) {
|
||||||
|
|
||||||
|
std::pair<std::string, std::string> h = { ip, port };
|
||||||
|
hosts.remove(h);
|
||||||
|
hosts.push_front(h);
|
||||||
|
if (hosts.size() > MAX_RECENT_HISTORY)
|
||||||
|
hosts.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::KnownHosts::remove(const string &ip)
|
||||||
|
{
|
||||||
|
for (auto hit = hosts.begin(); hit != hosts.end();) {
|
||||||
|
if ( ip.compare( hit->first ) > 0 )
|
||||||
|
++hit;
|
||||||
|
else
|
||||||
|
hit = hosts.erase(hit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Settings::Lock()
|
void Settings::Lock()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
19
Settings.h
19
Settings.h
@@ -126,6 +126,18 @@ struct History
|
|||||||
void validate();
|
void validate();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct KnownHosts
|
||||||
|
{
|
||||||
|
std::string protocol;
|
||||||
|
std::pair<std::string, std::string> default_host;
|
||||||
|
std::list< std::pair<std::string, std::string> > hosts;
|
||||||
|
|
||||||
|
KnownHosts() {}
|
||||||
|
|
||||||
|
void push(const std::string &ip, const std::string &port = "");
|
||||||
|
void remove(const std::string &ip);
|
||||||
|
};
|
||||||
|
|
||||||
struct TransitionConfig
|
struct TransitionConfig
|
||||||
{
|
{
|
||||||
bool cross_fade;
|
bool cross_fade;
|
||||||
@@ -250,8 +262,7 @@ struct Application
|
|||||||
bool accept_connections;
|
bool accept_connections;
|
||||||
int stream_protocol;
|
int stream_protocol;
|
||||||
int broadcast_port;
|
int broadcast_port;
|
||||||
std::string custom_connect_ip;
|
KnownHosts recentSRT;
|
||||||
std::string custom_connect_port;
|
|
||||||
|
|
||||||
// Settings of widgets
|
// Settings of widgets
|
||||||
WidgetsConfig widget;
|
WidgetsConfig widget;
|
||||||
@@ -307,8 +318,8 @@ struct Application
|
|||||||
accept_connections = false;
|
accept_connections = false;
|
||||||
stream_protocol = 0;
|
stream_protocol = 0;
|
||||||
broadcast_port = 7070;
|
broadcast_port = 7070;
|
||||||
custom_connect_ip = "127.0.0.1";
|
recentSRT.protocol = "srt://";
|
||||||
custom_connect_port = "8888";
|
recentSRT.default_host = { "127.0.0.1", "7070"};
|
||||||
pannel_current_session_mode = 0;
|
pannel_current_session_mode = 0;
|
||||||
current_view = 1;
|
current_view = 1;
|
||||||
current_workspace= 1;
|
current_workspace= 1;
|
||||||
|
|||||||
@@ -6731,7 +6731,7 @@ void Navigator::RenderNewPannel()
|
|||||||
else if (Settings::application.source.new_type == SOURCE_CONNECTED){
|
else if (Settings::application.source.new_type == SOURCE_CONNECTED){
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
if (ImGui::BeginCombo("##External", "Select device"))
|
if (ImGui::BeginCombo("##External", "Select stream"))
|
||||||
{
|
{
|
||||||
for (int d = 0; d < Device::manager().numDevices(); ++d){
|
for (int d = 0; d < Device::manager().numDevices(); ++d){
|
||||||
std::string namedev = Device::manager().name(d);
|
std::string namedev = Device::manager().name(d);
|
||||||
@@ -6758,36 +6758,90 @@ void Navigator::RenderNewPannel()
|
|||||||
|
|
||||||
// Indication
|
// Indication
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGuiToolkit::HelpToolTip("Create a source getting images from connected devices or machines;\n"
|
ImVec2 pos = ImGui::GetCursorPos();
|
||||||
|
ImGuiToolkit::HelpToolTip("Create a source capturing video streams from connected devices or machines;\n"
|
||||||
ICON_FA_CARET_RIGHT " webcams or frame grabbers\n"
|
ICON_FA_CARET_RIGHT " webcams or frame grabbers\n"
|
||||||
ICON_FA_CARET_RIGHT " screen capture\n"
|
ICON_FA_CARET_RIGHT " screen capture\n"
|
||||||
ICON_FA_CARET_RIGHT " stream shared by vimix on local network\n"
|
ICON_FA_CARET_RIGHT " shared by vimix on local network\n"
|
||||||
ICON_FA_CARET_RIGHT " SRT stream (e.g. broadcasted by vimix)");
|
ICON_FA_CARET_RIGHT " broadcasted with SRT over network.");
|
||||||
|
|
||||||
if (custom_connected) {
|
if (custom_connected) {
|
||||||
|
|
||||||
|
bool valid_ = false;
|
||||||
|
static std::string url_;
|
||||||
|
static std::string ip_ = Settings::application.recentSRT.hosts.empty() ? Settings::application.recentSRT.default_host.first : Settings::application.recentSRT.hosts.front().first;
|
||||||
|
static std::string port_ = Settings::application.recentSRT.hosts.empty() ? Settings::application.recentSRT.default_host.second : Settings::application.recentSRT.hosts.front().second;
|
||||||
|
static std::regex ipv4("(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])");
|
||||||
|
static std::regex numport("([0-9]){4,6}");
|
||||||
|
|
||||||
ImGui::Text("\nCall an SRT broadcaster:");
|
ImGui::Text("\nCall an SRT broadcaster:");
|
||||||
|
ImGui::SetCursorPos(pos + ImVec2(0.f, 1.8f * ImGui::GetFrameHeight()) );
|
||||||
|
ImGuiToolkit::Indication("Set the IP and Port for connecting with Secure Reliable Transport (SRT) protocol to a video broadcaster that is waiting for connections (listener mode).", ICON_FA_PODCAST);
|
||||||
|
|
||||||
|
// Entry field for IP
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
ImGuiToolkit::InputText("IP", &Settings::application.custom_connect_ip, ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsDecimal);
|
ImGuiToolkit::InputText("IP", &ip_, ImGuiInputTextFlags_CharsDecimal);
|
||||||
|
valid_ = std::regex_match(ip_, ipv4);
|
||||||
|
|
||||||
|
// Entry field for port
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
ImGuiToolkit::InputText("Port", &Settings::application.custom_connect_port, ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsDecimal);
|
ImGuiToolkit::InputText("Port", &port_, ImGuiInputTextFlags_CharsDecimal);
|
||||||
|
valid_ &= std::regex_match(port_, numport);
|
||||||
|
|
||||||
static char bufurl[32];
|
// URL generated from protorol, IP and port
|
||||||
ImFormatString(bufurl, IM_ARRAYSIZE(bufurl), "srt://%s:%s",
|
url_ = Settings::application.recentSRT.protocol + ip_ + ":" + port_;
|
||||||
Settings::application.custom_connect_ip.c_str(),
|
|
||||||
Settings::application.custom_connect_port.c_str() );
|
// push style for disabled text entry
|
||||||
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.8f));
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.8f));
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
|
||||||
ImGui::InputText("##url", bufurl, IM_ARRAYSIZE(bufurl), ImGuiInputTextFlags_ReadOnly);
|
// display default IP & port
|
||||||
|
if (Settings::application.recentSRT.hosts.empty()) {
|
||||||
|
ImGuiToolkit::InputText("##url", &url_, ImGuiInputTextFlags_ReadOnly);
|
||||||
|
}
|
||||||
|
// display most recent host & offer list of known hosts
|
||||||
|
else {
|
||||||
|
if (ImGui::BeginCombo("##SRThosts", url_.c_str())) {
|
||||||
|
for (auto it = Settings::application.recentSRT.hosts.begin(); it != Settings::application.recentSRT.hosts.end(); ++it) {
|
||||||
|
|
||||||
|
if (ImGui::Selectable( std::string(Settings::application.recentSRT.protocol + it->first + ":" + it->second).c_str() ) ) {
|
||||||
|
ip_ = it->first;
|
||||||
|
port_ = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
// icons to clear lists
|
||||||
|
ImVec2 pos_top = ImGui::GetCursorPos();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.7);
|
||||||
|
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear list")) {
|
||||||
|
Settings::application.recentSRT.hosts.clear();
|
||||||
|
ip_ = Settings::application.recentSRT.default_host.first;
|
||||||
|
port_ = Settings::application.recentSRT.default_host.second;
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
ImGui::SetCursorPos(pos_top);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop disabled style
|
||||||
ImGui::PopStyleColor(1);
|
ImGui::PopStyleColor(1);
|
||||||
|
|
||||||
ImGui::SameLine(0); ImGuiToolkit::Indication("URL for connecting with Secure Reliable Transport (SRT) protocol to a broadcaster that is waiting for connections (listener mode).", ICON_SOURCE_SRT);
|
// push a RED color style if host is not valid
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(0.0f, valid_ ? 0.0f : 0.6f, 0.4f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(0.0f, valid_ ? 0.0f : 0.7f, 0.3f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(0.0f, valid_ ? 0.0f : 0.8f, 0.2f));
|
||||||
|
|
||||||
if ( ImGui::Button("Call", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) {
|
// create a new SRT source if host is valid
|
||||||
new_source_preview_.setSource( Mixer::manager().createSourceSrt(Settings::application.custom_connect_ip, Settings::application.custom_connect_port), bufurl);
|
if ( ImGui::Button("Call", ImVec2(IMGUI_RIGHT_ALIGN, 0)) && valid_ ) {
|
||||||
|
// set preview source
|
||||||
|
new_source_preview_.setSource( Mixer::manager().createSourceSrt(ip_, port_), url_);
|
||||||
|
// remember known host
|
||||||
|
Settings::application.recentSRT.push(ip_, port_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user