mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-13 11:19: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 = ' ');
|
||||
|
||||
// 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
|
||||
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)
|
||||
{
|
||||
// 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("stream_protocol", application.stream_protocol);
|
||||
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);
|
||||
|
||||
// Widgets
|
||||
@@ -245,6 +259,17 @@ void Settings::Save(uint64_t runtime)
|
||||
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
|
||||
XMLElement *timerConfNode = xmlDoc.NewElement( "Timer" );
|
||||
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()
|
||||
{
|
||||
// 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("stream_protocol", &application.stream_protocol);
|
||||
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
|
||||
@@ -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
|
||||
XMLElement * timerconfnode = pRoot->FirstChildElement("Timer");
|
||||
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()
|
||||
{
|
||||
|
||||
|
||||
19
Settings.h
19
Settings.h
@@ -126,6 +126,18 @@ struct History
|
||||
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
|
||||
{
|
||||
bool cross_fade;
|
||||
@@ -250,8 +262,7 @@ struct Application
|
||||
bool accept_connections;
|
||||
int stream_protocol;
|
||||
int broadcast_port;
|
||||
std::string custom_connect_ip;
|
||||
std::string custom_connect_port;
|
||||
KnownHosts recentSRT;
|
||||
|
||||
// Settings of widgets
|
||||
WidgetsConfig widget;
|
||||
@@ -307,8 +318,8 @@ struct Application
|
||||
accept_connections = false;
|
||||
stream_protocol = 0;
|
||||
broadcast_port = 7070;
|
||||
custom_connect_ip = "127.0.0.1";
|
||||
custom_connect_port = "8888";
|
||||
recentSRT.protocol = "srt://";
|
||||
recentSRT.default_host = { "127.0.0.1", "7070"};
|
||||
pannel_current_session_mode = 0;
|
||||
current_view = 1;
|
||||
current_workspace= 1;
|
||||
|
||||
@@ -6731,7 +6731,7 @@ void Navigator::RenderNewPannel()
|
||||
else if (Settings::application.source.new_type == SOURCE_CONNECTED){
|
||||
|
||||
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){
|
||||
std::string namedev = Device::manager().name(d);
|
||||
@@ -6758,36 +6758,90 @@ void Navigator::RenderNewPannel()
|
||||
|
||||
// Indication
|
||||
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 " screen capture\n"
|
||||
ICON_FA_CARET_RIGHT " stream shared by vimix on local network\n"
|
||||
ICON_FA_CARET_RIGHT " SRT stream (e.g. broadcasted by vimix)");
|
||||
ICON_FA_CARET_RIGHT " shared by vimix on local network\n"
|
||||
ICON_FA_CARET_RIGHT " broadcasted with SRT over network.");
|
||||
|
||||
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::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);
|
||||
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);
|
||||
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];
|
||||
ImFormatString(bufurl, IM_ARRAYSIZE(bufurl), "srt://%s:%s",
|
||||
Settings::application.custom_connect_ip.c_str(),
|
||||
Settings::application.custom_connect_port.c_str() );
|
||||
// URL generated from protorol, IP and port
|
||||
url_ = Settings::application.recentSRT.protocol + ip_ + ":" + port_;
|
||||
|
||||
// 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::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::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)) ) {
|
||||
new_source_preview_.setSource( Mixer::manager().createSourceSrt(Settings::application.custom_connect_ip, Settings::application.custom_connect_port), bufurl);
|
||||
// create a new SRT source if host is valid
|
||||
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