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:
Bruno Herbelin
2022-09-08 20:36:58 +02:00
parent dd92f2dccb
commit 140ce358fa
4 changed files with 172 additions and 32 deletions

View File

@@ -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);

View File

@@ -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()
{

View File

@@ -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;

View File

@@ -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);
}
}