From ffa8e80213a5d60dd2bed4803ab96ebff6b9ef56 Mon Sep 17 00:00:00 2001 From: Andrea Bondavalli Date: Sat, 14 Jan 2023 19:24:43 +0100 Subject: [PATCH] Added "auto_sinks_update" to the daemon configuration parameters and to the WebUI. JSON boolean specifying whether to enable or disable the automatic update of the configured Sinks. When enabled the daemon will automatically update the configured Sinks according to the discovered remote sources via SAP and mDNS/RTSP updates. The SDP Originator (o=) is used to match a Sink with the remote source/s. --- README.md | 2 +- daemon/README.md | 8 +++++++- daemon/config.hpp | 6 ++++++ daemon/daemon.conf | 3 ++- daemon/json.cpp | 11 ++++++++--- daemon/session_manager.cpp | 12 +++++++----- daemon/tests/daemon.conf | 7 ++++--- daemon/tests/daemon_test.cpp | 2 ++ test/daemon.conf | 3 ++- webui/src/Config.jsx | 11 +++++++++-- webui/src/Services.js | 5 +++-- 11 files changed, 51 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 78a291f..b3b0757 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ The daemon can be cross-compiled for multiple platforms and implements the follo * control and configuration of up to 64 multicast and unicast sources and sinks using the ALSA RAVENNA/AES67 driver via netlink * session handling and SDP parsing and creation * HTTP REST API for the daemon control and configuration -* SAP sources discovery and advertisement compatible with AES67 standard +* SAP sources discovery, update and advertisement compatible with AES67 standard * mDNS sources discovery and advertisement (using Linux Avahi) compatible with Ravenna standard * RTSP client and server to retrieve, return and update SDP files via DESCRIBE and ANNOUNCE methods according to Ravenna standard * IGMP handling for SAP, PTP and RTP sessions diff --git a/daemon/README.md b/daemon/README.md index b16a126..08b7c05 100644 --- a/daemon/README.md +++ b/daemon/README.md @@ -12,6 +12,7 @@ The daemon is responsible for: * mDNS sources discovery and advertisement (using Linux Avahi) compatible with Ravenna standard * RTSP client and server to retrieve, return and update SDP files via DESCRIBE and ANNOUNCE methods according to Ravenna standard * IGMP handling for SAP, PTP and RTP sessions +* automatic update of Sinks based on discovered mDNS/SAP remote sources ## Configuration file ## @@ -187,7 +188,8 @@ Example "ip_addr": "127.0.0.1", "node_id": "AES67 daemon d9aca383", "custom_node_id": "", - "ptp_status_script": "./scripts/ptp_status.sh" + "ptp_status_script": "./scripts/ptp_status.sh", + "auto_sinks_update": true } where: @@ -269,6 +271,10 @@ where: > JSON string specifying the unique node identifier used to identify mDNS, SAP and SDP services announced by the daemon. > **_NOTE:_** This parameter is read-only and cannot be set. The server will determine the node id at startup time. +> **mauto\_sinks\_update** +> JSON boolean specifying whether to enable or disable the automatic update of the configured Sinks. +> **_NOTE:_** When enabled the daemon will automatically update the configured Sinks according to the discovered remote sources via SAP and mDNS/RTSP updates. The SDP Originator (o=) is used to match a Sink with the remote source/s. + > **custom\_node\_id** > JSON string specifying a custom node identifier used to identify mDNS, SAP and SDP services announced by the daemon. > When this parameter is empty the *node_id* is automatically generated by the daemon based on the current IP address. diff --git a/daemon/config.hpp b/daemon/config.hpp index 003ee69..7ad5344 100644 --- a/daemon/config.hpp +++ b/daemon/config.hpp @@ -54,6 +54,7 @@ class Config { const std::string& get_config_filename() const { return config_filename_; }; const std::string& get_custom_node_id() const { return custom_node_id_; }; std::string get_node_id() const; + bool get_auto_sinks_update() const { return auto_sinks_update_; }; /* attributes set during init */ const std::array& get_mac_addr() const { return mac_addr_; }; @@ -122,6 +123,9 @@ class Config { void set_custom_node_id(const std::string& node_id) { custom_node_id_ = node_id; }; + void set_auto_sinks_update(bool auto_sinks_update) { + auto_sinks_update_ = auto_sinks_update; + }; void set_driver_restart(bool restart) { driver_restart_ = restart; } friend bool operator!=(const Config& lhs, const Config& rhs) { @@ -144,6 +148,7 @@ class Config { lhs.get_status_file() != rhs.get_status_file() || lhs.get_interface_name() != rhs.get_interface_name() || lhs.get_mdns_enabled() != rhs.get_mdns_enabled() || + lhs.get_auto_sinks_update() != rhs.get_auto_sinks_update() || lhs.get_custom_node_id() != rhs.get_custom_node_id(); }; friend bool operator==(const Config& lhs, const Config& rhs) { @@ -174,6 +179,7 @@ class Config { std::string ptp_status_script_; std::string custom_node_id_; std::string node_id_; + bool auto_sinks_update_{true}; /* set during init */ std::array mac_addr_{0, 0, 0, 0, 0, 0}; diff --git a/daemon/daemon.conf b/daemon/daemon.conf index b049a64..58e1cec 100644 --- a/daemon/daemon.conf +++ b/daemon/daemon.conf @@ -19,5 +19,6 @@ "interface_name": "lo", "mdns_enabled": true, "custom_node_id": "", - "ptp_status_script": "./scripts/ptp_status.sh" + "ptp_status_script": "./scripts/ptp_status.sh", + "auto_sinks_update": true } diff --git a/daemon/json.cpp b/daemon/json.cpp index fbbdf87..a395976 100644 --- a/daemon/json.cpp +++ b/daemon/json.cpp @@ -99,13 +99,16 @@ std::string config_to_json(const Config& config) { << ",\n \"interface_name\": \"" << escape_json(config.get_interface_name()) << "\"" << ",\n \"mdns_enabled\": " << std::boolalpha << config.get_mdns_enabled() - << ",\n \"custom_node_id\": \"" << escape_json(config.get_custom_node_id()) << "\"" + << ",\n \"custom_node_id\": \"" + << escape_json(config.get_custom_node_id()) << "\"" << ",\n \"node_id\": \"" << escape_json(config.get_node_id()) << "\"" << ",\n \"ptp_status_script\": \"" << escape_json(config.get_ptp_status_script()) << "\"" - << ",\n \"mac_addr\": \"" << escape_json(config.get_mac_addr_str()) << "\"" + << ",\n \"mac_addr\": \"" << escape_json(config.get_mac_addr_str()) + << "\"" << ",\n \"ip_addr\": \"" << escape_json(config.get_ip_addr_str()) << "\"" - << "\n}\n"; + << ",\n \"auto_sinks_update\": " << std::boolalpha + << config.get_auto_sinks_update() << "\n}\n"; return ss.str(); } @@ -327,6 +330,8 @@ Config json_to_config_(std::istream& js, Config& config) { } else if (key == "custom_node_id") { config.set_custom_node_id( remove_undesired_chars(val.get_value())); + } else if (key == "auto_sinks_update") { + config.set_auto_sinks_update(val.get_value()); } else if (key == "mac_addr" || key == "ip_addr" || key == "node_id") { /* ignored */ } else { diff --git a/daemon/session_manager.cpp b/daemon/session_manager.cpp index 706f273..6ead695 100644 --- a/daemon/session_manager.cpp +++ b/daemon/session_manager.cpp @@ -1055,11 +1055,13 @@ std::list SessionManager::get_updated_sinks( } void SessionManager::update_sinks(const std::list& sources_list) { - auto sinks_list = get_updated_sinks(sources_list); - for (auto& sink : sinks_list) { - // Re-add sink with new SDP, since the sink.id is the same there will be - // an update - add_sink(sink); + if (config_->get_auto_sinks_update()) { + auto sinks_list = get_updated_sinks(sources_list); + for (auto& sink : sinks_list) { + // Re-add sink with new SDP, since the sink.id is the same there will be + // an update + add_sink(sink); + } } } diff --git a/daemon/tests/daemon.conf b/daemon/tests/daemon.conf index 853fd97..7831362 100644 --- a/daemon/tests/daemon.conf +++ b/daemon/tests/daemon.conf @@ -18,9 +18,10 @@ "status_file": "", "interface_name": "lo", "mdns_enabled": true, - "mac_addr": "00:00:00:00:00:00", - "ip_addr": "127.0.0.1", "custom_node_id": "test node", "node_id": "test node", - "ptp_status_script": "" + "ptp_status_script": "", + "mac_addr": "00:00:00:00:00:00", + "ip_addr": "127.0.0.1", + "auto_sinks_update": true } diff --git a/daemon/tests/daemon_test.cpp b/daemon/tests/daemon_test.cpp index bb7501f..1b6ddad 100644 --- a/daemon/tests/daemon_test.cpp +++ b/daemon/tests/daemon_test.cpp @@ -398,6 +398,7 @@ BOOST_AUTO_TEST_CASE(get_config) { auto interface_name = pt.get("interface_name"); auto mac_addr = pt.get("mac_addr"); auto ip_addr = pt.get("ip_addr"); + auto auto_sinks_update = pt.get("auto_sinks_update"); BOOST_CHECK_MESSAGE(http_port == 9999, "config as excepcted"); // BOOST_CHECK_MESSAGE(log_severity == 5, "config as excepcted"); BOOST_CHECK_MESSAGE(playout_delay == 0, "config as excepcted"); @@ -419,6 +420,7 @@ BOOST_AUTO_TEST_CASE(get_config) { BOOST_CHECK_MESSAGE(ptp_status_script == "", "config as excepcted"); BOOST_CHECK_MESSAGE(node_id == "test node", "config as excepcted"); BOOST_CHECK_MESSAGE(custom_node_id == "test node", "config as excepcted"); + BOOST_CHECK_MESSAGE(auto_sinks_update == true, "config as excepcted"); } BOOST_AUTO_TEST_CASE(get_ptp_status) { diff --git a/test/daemon.conf b/test/daemon.conf index 279bae0..bf88a92 100644 --- a/test/daemon.conf +++ b/test/daemon.conf @@ -22,5 +22,6 @@ "ip_addr": "127.0.0.1", "node_id": "AES67 daemon 007f0100", "custom_node_id": "", - "ptp_status_script": "" + "ptp_status_script": "", + "auto_sinks_update": true } diff --git a/webui/src/Config.jsx b/webui/src/Config.jsx index ecc6513..fab35e9 100644 --- a/webui/src/Config.jsx +++ b/webui/src/Config.jsx @@ -59,7 +59,8 @@ class Config extends Component { ipAddr: '', errors: 0, isConfigLoading: false, - isVersionLoading: false + isVersionLoading: false, + autoSinksUpdate: false }; this.onSubmit = this.onSubmit.bind(this); this.inputIsValid = this.inputIsValid.bind(this); @@ -104,6 +105,7 @@ class Config extends Component { macAddr: data.mac_addr, ipAddr: data.ip_addr, nodeId: data.node_id, + autoSinksUpdate: data.auto_sinks_update, isConfigLoading: false })) .catch(err => this.setState({isConfigLoading: false})); @@ -139,7 +141,8 @@ class Config extends Component { this.state.sapMcastAddr, this.state.sapInterval, this.state.mdnsEnabled, - this.state.customNodeId) + this.state.customNodeId, + this.state.autoSinksUpdate) .then(response => toast.success('Applying new configuration ...')); } @@ -226,6 +229,10 @@ class Config extends Component { this.setState({mdnsEnabled: e.target.checked})} checked={this.state.mdnsEnabled ? true : undefined}/> + + + this.setState({autoSinksUpdate: e.target.checked})} checked={this.state.autoSinksUpdate ? true : undefined}/> + diff --git a/webui/src/Services.js b/webui/src/Services.js index 35ffab6..d3a6174 100644 --- a/webui/src/Services.js +++ b/webui/src/Services.js @@ -84,7 +84,7 @@ export default class RestAPI { }); } - static setConfig(log_severity, syslog_proto, syslog_server, rtp_mcast_base, rtp_port, rtsp_port, playout_delay, tic_frame_size_at_1fs, sample_rate, max_tic_frame_size, sap_mcast_addr, sap_interval, mdns_enabled, custom_node_id) { + static setConfig(log_severity, syslog_proto, syslog_server, rtp_mcast_base, rtp_port, rtsp_port, playout_delay, tic_frame_size_at_1fs, sample_rate, max_tic_frame_size, sap_mcast_addr, sap_interval, mdns_enabled, custom_node_id, auto_sinks_update) { return this.doFetch(config, { body: JSON.stringify({ log_severity: parseInt(log_severity, 10), @@ -100,7 +100,8 @@ export default class RestAPI { sap_mcast_addr: sap_mcast_addr, sap_interval: parseInt(sap_interval, 10), custom_node_id: custom_node_id, - mdns_enabled: mdns_enabled + mdns_enabled: mdns_enabled, + auto_sinks_update: auto_sinks_update }), method: 'POST' }).catch(err => {