Enhancement of daemon reconfiguration and PTP status update notification via shell script. See #82

The daemon can apply a configuration change to the following parameters without a restart:
    sap_interval, syslog_proto, syslog_server, log_severity, sample_rate

The daemon can apply a configuration change to the following parameters without a light restart:
    http_port, rtsp_port, http_base_dir, rtp_mcast_base, sap_mcast_addr, rtp_port, rtp_port, status_file, interface_name, mdns_enabled

A light restart means that the configuration can be applied without interrupting the playback/capture applications

A change to one of following paramters causes a full daemon restart:
    interface_name, tic_frame_size_at_1fs, max_tic_frame_size

On PTP status change the daemon can run in background an external shell script whose path name is specified by the new ptp_status_script Config parameter.
If this parameter is empty, no script is invoked. The PTP clock status is passed as first parameter to the script and it can be unlocked, locking or locked.
A sample script is provided in daemon/scripts/ptp_status.sh
This commit is contained in:
Andrea Bondavalli 2022-05-19 19:04:26 +02:00
parent cde35a7b7c
commit dbb593120a
23 changed files with 231 additions and 77 deletions

View File

@ -185,7 +185,8 @@ Example
"sap_interval": 30,
"mac_addr": "01:00:5e:01:00:01",
"ip_addr": "127.0.0.1",
"node_id": "AES67 daemon ubuntu-d9aca383"
"node_id": "AES67 daemon ubuntu-d9aca383",
"ptp_status_script": "./scripts/ptp_status.sh"
}
where:
@ -221,7 +222,7 @@ where:
> The specific multicast RTP address is the base address plus the source id number.
> For example if the base address is 239.2.0.1 and source id is 1 the RTP source address used is 239.2.0.2.
> **rtp_port**
> **rtp\_port**
> JSON number specifying the RTP port used by the sources.
> **ptp\_domain**
@ -267,6 +268,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.
> **ptp\_status\_script**
> JSON string specifying the path to the script executed in background when the PTP slave clock status changes.
> The PTP clock status is passed as first parameter to the script and it can be *unlocked*, *locking* or *locked*.
### JSON PTP Config<a name="ptp-config"></a> ###
Example

View File

@ -101,9 +101,9 @@ bool Browser::worker() {
duration_cast<second_t>(steady_clock::now() - startup_).count();
auto upd_source{*it};
if ((last_seen - upd_source.last_seen) != 0) {
upd_source.announce_period = last_seen - upd_source.last_seen;
upd_source.last_seen = last_seen;
sources_.replace(it, upd_source);
upd_source.announce_period = last_seen - upd_source.last_seen;
upd_source.last_seen = last_seen;
sources_.replace(it, upd_source);
}
} else {
BOOST_LOG_TRIVIAL(info) << "browser:: removing SAP source " << it->id

View File

@ -36,7 +36,8 @@
using namespace boost::asio;
std::shared_ptr<Config> Config::parse(const std::string& filename) {
std::shared_ptr<Config> Config::parse(const std::string& filename,
bool driver_restart) {
Config config;
std::ifstream jsonstream(filename);
@ -104,20 +105,43 @@ std::shared_ptr<Config> Config::parse(const std::string& filename) {
}
config.config_filename_ = filename;
config.need_restart_ = false;
config.daemon_restart_ = false;
config.driver_restart_ = driver_restart;
return std::make_shared<Config>(config);
}
bool Config::save(const Config& config, bool need_restart) {
std::ofstream js(config_filename_);
if (!js) {
BOOST_LOG_TRIVIAL(fatal)
<< "Config:: cannot save to file " << config_filename_;
return false;
bool Config::save(const Config& config) {
if (*this != config) {
std::ofstream js(config_filename_);
if (!js) {
BOOST_LOG_TRIVIAL(fatal)
<< "Config:: cannot save to file " << config_filename_;
return false;
}
js << config_to_json(config);
driver_restart_ =
get_tic_frame_size_at_1fs() != config.get_tic_frame_size_at_1fs() ||
get_max_tic_frame_size() != config.get_max_tic_frame_size() ||
get_interface_name() != config.get_interface_name();
daemon_restart_ = driver_restart_ ||
get_http_port() != config.get_http_port() ||
get_rtsp_port() != config.get_rtsp_port() ||
get_http_base_dir() != config.get_http_base_dir() ||
get_rtp_mcast_base() != config.get_rtp_mcast_base() ||
get_sap_mcast_addr() != config.get_sap_mcast_addr() ||
get_rtp_port() != config.get_rtp_port() ||
get_status_file() != config.get_status_file() ||
get_mdns_enabled() != config.get_mdns_enabled();
if (!daemon_restart_)
*this = config;
BOOST_LOG_TRIVIAL(info) << "Config:: file saved";
} else {
BOOST_LOG_TRIVIAL(info) << "Config:: unchanged";
}
js << config_to_json(config);
BOOST_LOG_TRIVIAL(info) << "Config:: file saved";
need_restart_ = need_restart;
return true;
}

View File

@ -27,9 +27,10 @@
class Config {
public:
/* save new config to json file */
bool save(const Config& config, bool need_restart = true);
bool save(const Config& config);
/* build config from json file */
static std::shared_ptr<Config> parse(const std::string& filename);
static std::shared_ptr<Config> parse(const std::string& filename,
bool driver_restart);
/* attributes retrieved from config json */
uint16_t get_http_port() const { return http_port_; };
@ -57,9 +58,13 @@ class Config {
const std::string& get_mac_addr_str() const { return mac_str_; };
uint32_t get_ip_addr() const { return ip_addr_; };
const std::string& get_ip_addr_str() const { return ip_str_; };
bool get_need_restart() const { return need_restart_; };
bool get_daemon_restart() const { return daemon_restart_; };
bool get_driver_restart() const { return driver_restart_; };
bool get_mdns_enabled() const { return mdns_enabled_; };
int get_interface_idx() { return interface_idx_; };
const std::string& get_ptp_status_script() const {
return ptp_status_script_;
}
void set_http_port(uint16_t http_port) { http_port_ = http_port; };
void set_rtsp_port(uint16_t rtsp_port) { rtsp_port_ = rtsp_port; };
@ -109,6 +114,35 @@ class Config {
};
void set_mdns_enabled(bool enabled) { mdns_enabled_ = enabled; };
void set_interface_idx(int index) { interface_idx_ = index; };
void set_ptp_status_script(const std::string& script) {
ptp_status_script_ = script;
};
void set_driver_restart(bool restart) { driver_restart_ = restart; }
friend bool operator!=(const Config& lhs, const Config& rhs) {
return lhs.get_http_port() != rhs.get_http_port() ||
lhs.get_rtsp_port() != rhs.get_rtsp_port() ||
lhs.get_http_base_dir() != rhs.get_http_base_dir() ||
lhs.get_log_severity() != rhs.get_log_severity() ||
lhs.get_playout_delay() != rhs.get_playout_delay() ||
lhs.get_tic_frame_size_at_1fs() != rhs.get_tic_frame_size_at_1fs() ||
lhs.get_max_tic_frame_size() != rhs.get_max_tic_frame_size() ||
lhs.get_sample_rate() != rhs.get_sample_rate() ||
lhs.get_rtp_mcast_base() != rhs.get_rtp_mcast_base() ||
lhs.get_sap_mcast_addr() != rhs.get_sap_mcast_addr() ||
lhs.get_rtp_port() != rhs.get_rtp_port() ||
lhs.get_ptp_domain() != rhs.get_ptp_domain() ||
lhs.get_ptp_dscp() != rhs.get_ptp_dscp() ||
lhs.get_sap_interval() != rhs.get_sap_interval() ||
lhs.get_syslog_proto() != rhs.get_syslog_proto() ||
lhs.get_syslog_server() != rhs.get_syslog_server() ||
lhs.get_status_file() != rhs.get_status_file() ||
lhs.get_interface_name() != rhs.get_interface_name() ||
lhs.get_mdns_enabled() != rhs.get_mdns_enabled();
};
friend bool operator==(const Config& lhs, const Config& rhs) {
return !(lhs != rhs);
};
private:
/* from json */
@ -131,6 +165,7 @@ class Config {
std::string status_file_{"./status.json"};
std::string interface_name_{"eth0"};
bool mdns_enabled_{true};
std::string ptp_status_script_;
/* set during init */
std::array<uint8_t, 6> mac_addr_{0, 0, 0, 0, 0, 0};
@ -140,8 +175,10 @@ class Config {
int interface_idx_;
std::string config_filename_;
/* reconfig needs driver restart */
bool driver_restart_{true};
/* reconfig needs daemon restart */
bool need_restart_{false};
bool daemon_restart_{false};
};
#endif

View File

@ -16,6 +16,7 @@
"syslog_proto": "none",
"syslog_server": "255.255.255.254:1234",
"status_file": "./status.json",
"interface_name": "lo",
"mdns_enabled": true,
"interface_name": "lo"
"ptp_status_script": "./scripts/ptp_status.sh"
}

View File

@ -130,7 +130,7 @@ bool DriverHandler::event_receiver() {
return true;
}
bool DriverHandler::terminate() {
bool DriverHandler::terminate(const Config& /* config */) {
if (running_) {
running_ = false;
client_u2k_.terminate();

View File

@ -40,10 +40,10 @@ class DriverHandler {
DriverHandler(){};
DriverHandler(const DriverHandler&) = delete;
DriverHandler& operator=(const DriverHandler&) = delete;
virtual ~DriverHandler() { terminate(); };
virtual ~DriverHandler(){};
virtual bool init(const Config& config);
virtual bool terminate();
virtual bool terminate(const Config& config);
protected:
virtual void send_command(enum MT_ALSA_msg_id id,

View File

@ -81,20 +81,28 @@ bool DriverManager::init(const Config& config) {
ptp_config.ui8Domain = config.get_ptp_domain();
ptp_config.ui8DSCP = config.get_ptp_dscp();
bool res = hello() || start() || reset() ||
set_interface_name(config.get_interface_name()) ||
set_ptp_config(ptp_config) ||
set_tic_frame_size_at_1fs(config.get_tic_frame_size_at_1fs()) ||
set_playout_delay(config.get_playout_delay()) ||
set_max_tic_frame_size(config.get_max_tic_frame_size());
if (hello())
return false;
bool res(false);
if (config.get_driver_restart()) {
res = start() || reset() ||
set_interface_name(config.get_interface_name()) ||
set_ptp_config(ptp_config) ||
set_tic_frame_size_at_1fs(config.get_tic_frame_size_at_1fs()) ||
set_playout_delay(config.get_playout_delay()) ||
set_max_tic_frame_size(config.get_max_tic_frame_size());
}
return !res;
}
bool DriverManager::terminate() {
stop();
bool DriverManager::terminate(const Config& config) {
if (config.get_driver_restart()) {
stop();
}
bye();
return DriverHandler::terminate();
return DriverHandler::terminate(config);
}
std::error_code DriverManager::hello() {

View File

@ -33,7 +33,7 @@ class DriverManager : public DriverHandler {
// driver interface
bool init(const Config& config) override;
bool terminate() override;
bool terminate(const Config& config) override;
std::error_code ping(); // unused, return error
std::error_code set_ptp_config(const TPTPConfig& config);

View File

@ -115,6 +115,30 @@ bool HttpServer::init() {
svr_.Post("/api/config", [this](const Request& req, Response& res) {
try {
Config config = json_to_config(req.body, *config_);
if (config_->get_syslog_proto() != config.get_syslog_proto() ||
config_->get_syslog_server() != config.get_syslog_server() ||
config_->get_log_severity() != config.get_log_severity()) {
log_init(config);
}
std::error_code ret;
if (config_->get_playout_delay() != config.get_playout_delay()) {
ret = session_manager_->set_driver_config("playout_delay",
config.get_playout_delay());
}
if (config_->get_sample_rate() != config.get_sample_rate()) {
ret = session_manager_->set_driver_config("sample_rate",
config.get_sample_rate());
}
if (config_->get_ptp_domain() != config.get_ptp_domain() ||
config_->get_ptp_dscp() != config.get_ptp_dscp()) {
PTPConfig ptpConfig{config.get_ptp_domain(), config.get_ptp_dscp()};
ret = session_manager_->set_ptp_config(ptpConfig);
}
if (ret) {
set_error(ret, "failed to set config", res);
return;
}
if (!config_->save(config)) {
set_error(500, "failed to save config", res);
return;
@ -153,7 +177,7 @@ bool HttpServer::init() {
Config config(*config_);
config.set_ptp_domain(ptpConfig.domain);
config.set_ptp_dscp(ptpConfig.dscp);
if (!config_->save(config, false)) {
if (!config_->save(config)) {
set_error(500, "failed to save config", res);
return;
}

View File

@ -115,7 +115,6 @@ int get_interface_index(const std::string& interface_name) {
return ifr.ifr_ifindex;
}
std::pair<std::array<uint8_t, 6>, std::string> get_mac_from_arp_cache(
const std::string& interface_name,
const std::string& ip) {
@ -155,7 +154,6 @@ std::pair<std::array<uint8_t, 6>, std::string> get_mac_from_arp_cache(
return {mac, ""};
}
bool ping(const std::string& ip) {
static uint16_t sequence_number(0);
uint16_t identifier(0xABAB);
@ -182,7 +180,6 @@ bool ping(const std::string& ip) {
return true;
}
bool echo_try_connect(const std::string& ip) {
ip::tcp::iostream s;
BOOST_LOG_TRIVIAL(debug) << "echo_connect:: connecting to " << ip;

View File

@ -104,6 +104,8 @@ std::string config_to_json(const Config& config) {
<< ",\n \"ip_addr\": \"" << escape_json(config.get_ip_addr_str()) << "\""
<< ",\n \"node_id\": \"" << escape_json(get_node_id(config.get_ip_addr()))
<< "\""
<< ",\n \"ptp_status_script\": \""
<< escape_json(config.get_ptp_status_script()) << "\""
<< "\n}\n";
return ss.str();
}
@ -158,8 +160,8 @@ std::string sink_to_json(const StreamSink& sink) {
std::string sink_status_to_json(const SinkStreamStatus& status) {
std::stringstream ss;
ss << "{";
ss << " \n \"sink_flags\":\n {" << std::boolalpha
<< " \n \"rtp_seq_id_error\": " << status.is_rtp_seq_id_error
ss << "\n \"sink_flags\":\n {" << std::boolalpha
<< " \n \"rtp_seq_id_error\": " << status.is_rtp_seq_id_error
<< ", \n \"rtp_ssrc_error\": " << status.is_rtp_ssrc_error
<< ", \n \"rtp_payload_type_error\": "
<< status.is_rtp_payload_type_error
@ -320,6 +322,9 @@ Config json_to_config_(std::istream& js, Config& config) {
} else if (key == "syslog_server") {
config.set_syslog_server(
remove_undesired_chars(val.get_value<std::string>()));
} else if (key == "ptp_status_script") {
config.set_ptp_status_script(
remove_undesired_chars(val.get_value<std::string>()));
} else if (key == "mac_addr" || key == "ip_addr" || key == "node_id") {
/* ignored */
} else {

View File

@ -35,7 +35,7 @@ namespace po = boost::program_options;
namespace postyle = boost::program_options::command_line_style;
namespace logging = boost::log;
static std::string version("bondagit-1.4");
static std::string version("bondagit-1.5");
static std::atomic<bool> terminate = false;
void termination_handler(int signum) {
@ -53,15 +53,16 @@ const std::string& get_version() {
}
int main(int argc, char* argv[]) {
int rc = EXIT_SUCCESS;
int rc(EXIT_SUCCESS);
po::options_description desc("Options");
desc.add_options()
("version,v", "Print daemon version and exit")
("config,c", po::value<std::string>()->default_value("/etc/daemon.conf"),
"daemon configuration file")
("http_port,p", po::value<int>(), "HTTP server port")
("help,h", "Print this help message");
desc.add_options()("version,v", "Print daemon version and exit")(
"config,c", po::value<std::string>()->default_value("/etc/daemon.conf"),
"daemon configuration file")("http_port,p", po::value<int>(),
"HTTP server port")("help,h",
"Print this help "
"message");
int unix_style = postyle::unix_style | postyle::short_allow_next;
bool driver_restart(true);
po::variables_map vm;
try {
@ -98,7 +99,7 @@ int main(int argc, char* argv[]) {
while (!is_terminated() && rc == EXIT_SUCCESS) {
/* load configuration from file */
auto config = Config::parse(filename);
auto config = Config::parse(filename, driver_restart);
if (config == nullptr) {
return EXIT_FAILURE;
}
@ -165,7 +166,8 @@ int main(int argc, char* argv[]) {
break;
}
if (config->get_need_restart()) {
driver_restart = config->get_driver_restart();
if (config->get_daemon_restart()) {
BOOST_LOG_TRIVIAL(warning) << "main:: config changed, restarting ...";
break;
}
@ -205,7 +207,7 @@ int main(int argc, char* argv[]) {
}
/* stop driver manager */
if (!driver->terminate()) {
if (!driver->terminate(*config)) {
throw std::runtime_error(
std::string("DriverManager:: terminate failed"));
}

View File

@ -25,7 +25,6 @@
#include "rtsp_client.hpp"
#include "mdns_client.hpp"
#ifdef _USE_AVAHI_
void MDNSClient::resolve_callback(AvahiServiceResolver* r,
AvahiIfIndex interface,

View File

@ -25,7 +25,6 @@
#include "utils.hpp"
#include "mdns_server.hpp"
#ifdef _USE_AVAHI_
struct AvahiLockGuard {
AvahiLockGuard() = delete;

View File

@ -15,7 +15,6 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "utils.hpp"
#include "rtsp_server.hpp"

11
daemon/scripts/ptp_status.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
if [ $1 == "locked" ]; then
echo "$0 >> PTP locked";
#speaker-test -D plughw:RAVENNA -r 48000 -c 2 -t sine &
elif [ $1 == "locking" ]; then
echo "$0 >> PTP locking";
elif [ $1 == "unlocked" ]; then
echo "$0 >> PTP unlocked";
#killall -9 speaker-test
fi

View File

@ -19,6 +19,7 @@
#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH 4096 // max for SDP file
#include <stdlib.h>
#include <httplib.h>
#include <boost/algorithm/string.hpp>
@ -479,7 +480,7 @@ std::error_code SessionManager::add_source(const StreamSource& source) {
info.stream.m_ui32CRTP_stream_info_sizeof = sizeof(info.stream);
strncpy(info.stream.m_cName, source.name.c_str(),
sizeof(info.stream.m_cName) - 1);
info.stream.m_ucDSCP = source.dscp; // IPv4 DSCP
info.stream.m_ucDSCP = source.dscp; // IPv4 DSCP
info.stream.m_byPayloadType = source.payload_type;
info.stream.m_byWordLength = get_codec_word_lenght(source.codec);
info.stream.m_byNbOfChannels = source.map.size();
@ -513,13 +514,16 @@ std::error_code SessionManager::add_source(const StreamSource& source) {
info.stream.m_ui8DestMAC);
info.stream.m_byTTL = source.ttl;
} else {
auto mac_addr = get_mac_from_arp_cache(config_->get_interface_name(),
auto mac_addr = get_mac_from_arp_cache(
config_->get_interface_name(),
ip::address_v4(info.stream.m_ui32DestIP).to_string());
int retry = 3;
while (!mac_addr.second.length() && retry--) {
// if not in cache already try to populate the MAC cache
(void)echo_try_connect(ip::address_v4(info.stream.m_ui32DestIP).to_string());
mac_addr = get_mac_from_arp_cache(config_->get_interface_name(),
(void)echo_try_connect(
ip::address_v4(info.stream.m_ui32DestIP).to_string());
mac_addr = get_mac_from_arp_cache(
config_->get_interface_name(),
ip::address_v4(info.stream.m_ui32DestIP).to_string());
}
if (!mac_addr.second.length()) {
@ -625,8 +629,8 @@ std::string SessionManager::get_source_sdp_(uint32_t id,
if (IN_MULTICAST(info.stream.m_ui32DestIP)) {
ss << "/" << static_cast<unsigned>(info.stream.m_byTTL);
}
ss << "\na=rtpmap:" << static_cast<unsigned>(info.stream.m_byPayloadType) << " "
<< info.stream.m_cCodec << "/" << sample_rate << "/"
ss << "\na=rtpmap:" << static_cast<unsigned>(info.stream.m_byPayloadType)
<< " " << info.stream.m_cCodec << "/" << sample_rate << "/"
<< static_cast<unsigned>(info.stream.m_byNbOfChannels) << "\n"
<< "a=sync-time:0\n"
<< "a=framecount:" << info.stream.m_ui32MaxSamplesPerPacket << "\n"
@ -902,6 +906,19 @@ std::error_code SessionManager::get_sink_status(
return ret;
}
std::error_code SessionManager::set_driver_config(const std::string& name,
uint32_t value) const {
if (name == "sample_rate")
return driver_->set_sample_rate(value);
else if (name == "tic_frame_size_at_1fs")
return driver_->set_tic_frame_size_at_1fs(value);
else if (name == "set_max_tic_frame_size")
return driver_->set_max_tic_frame_size(value);
else if (name == "playout_delay")
return driver_->set_playout_delay(value);
return DriverErrc::unknown;
}
std::error_code SessionManager::set_ptp_config(const PTPConfig& config) {
TPTPConfig ptp_config;
ptp_config.ui8Domain = config.domain;
@ -1002,9 +1019,31 @@ void SessionManager::on_update_sources() {
g_session_version++;
}
void SessionManager::on_ptp_status_locked() const {
// set sample rate, this may require seconds
(void)driver_->set_sample_rate(driver_->get_current_sample_rate());
void SessionManager::on_ptp_status_changed(const std::string& status) const {
if (status == "locked") {
// set sample rate, this may require seconds
(void)driver_->set_sample_rate(driver_->get_current_sample_rate());
}
static std::string g_ptp_status;
if (g_ptp_status != status && !config_->get_ptp_status_script().empty()) {
pid_t pid = fork();
if (pid == 0) {
/* child */
int fdlimit = (int)sysconf(_SC_OPEN_MAX);
/* close all partent's fds */
for (int i = STDERR_FILENO + 1; i < fdlimit; i++)
close(i);
char* argv_list[] = {const_cast<char*>(config_->get_ptp_status_script().c_str()),
const_cast<char*>(status.c_str()), NULL};
execv(config_->get_ptp_status_script().c_str(), argv_list);
exit(0);
}
g_ptp_status = status;
}
}
using namespace std::chrono;
@ -1043,7 +1082,7 @@ bool SessionManager::worker() {
pui64GMID[5], pui64GMID[6], pui64GMID[7]);
bool ptp_changed_gmid = false;
bool ptp_changed_to_locked = false;
std::string ptp_status_changed_to;
// update PTP clock status
ptp_mutex_.lock();
// update status
@ -1069,15 +1108,13 @@ bool SessionManager::worker() {
BOOST_LOG_TRIVIAL(info)
<< "session_manager:: new PTP clock status " << new_ptp_status;
ptp_status_.status = new_ptp_status;
if (new_ptp_status == "locked") {
ptp_changed_to_locked = true;
}
ptp_status_changed_to = new_ptp_status;
}
// end update PTP clock status
ptp_mutex_.unlock();
if (ptp_changed_to_locked) {
on_ptp_status_locked();
if (!ptp_status_changed_to.empty()) {
on_ptp_status_changed(ptp_status_changed_to);
}
if (ptp_changed_gmid ||
@ -1085,10 +1122,10 @@ bool SessionManager::worker() {
/* master clock id changed or sample rate changed
* we need to update all the sources */
if (sample_rate != driver_->get_current_sample_rate()) {
sample_rate = driver_->get_current_sample_rate();
// set driver sample rate
(void)driver_->set_sample_rate(sample_rate);
}
sample_rate = driver_->get_current_sample_rate();
// set driver sample rate
(void)driver_->set_sample_rate(sample_rate);
}
on_update_sources();
}
}

View File

@ -151,6 +151,8 @@ class SessionManager {
uint8_t get_sink_id(const std::string& name) const;
std::error_code set_ptp_config(const PTPConfig& config);
std::error_code set_driver_config(const std::string& name,
uint32_t value) const;
void get_ptp_config(PTPConfig& config) const;
void get_ptp_status(PTPStatus& status) const;
@ -169,7 +171,7 @@ class SessionManager {
void on_add_sink(const StreamSink& sink, const StreamInfo& info);
void on_remove_sink(const StreamInfo& info);
void on_ptp_status_locked() const;
void on_ptp_status_changed(const std::string& status) const;
void on_update_sources();

View File

@ -20,5 +20,6 @@
"mdns_enabled": true,
"mac_addr": "00:00:00:00:00:00",
"ip_addr": "127.0.0.1",
"node_id": "AES67 daemon 007f0100"
"node_id": "AES67 daemon 007f0100",
"ptp_status_script": ""
}

View File

@ -392,6 +392,7 @@ BOOST_AUTO_TEST_CASE(get_config) {
auto syslog_proto = pt.get<std::string>("syslog_proto");
auto syslog_server = pt.get<std::string>("syslog_server");
auto status_file = pt.get<std::string>("status_file");
auto ptp_status_script = pt.get<std::string>("ptp_status_script");
auto interface_name = pt.get<std::string>("interface_name");
auto mac_addr = pt.get<std::string>("mac_addr");
auto ip_addr = pt.get<std::string>("ip_addr");
@ -413,6 +414,7 @@ BOOST_AUTO_TEST_CASE(get_config) {
BOOST_CHECK_MESSAGE(interface_name == "lo", "config as excepcted");
BOOST_CHECK_MESSAGE(mac_addr == "00:00:00:00:00:00", "config as excepcted");
BOOST_CHECK_MESSAGE(ip_addr == "127.0.0.1", "config as excepcted");
BOOST_CHECK_MESSAGE(ptp_status_script == "", "config as excepcted");
}
BOOST_AUTO_TEST_CASE(get_ptp_status) {

View File

@ -20,5 +20,6 @@
"mdns_enabled": false,
"mac_addr": "00:00:00:00:00:00",
"ip_addr": "127.0.0.1",
"node_id": "AES67 daemon 007f0100"
"node_id": "AES67 daemon 007f0100",
"ptp_status_script": ""
}

View File

@ -135,7 +135,7 @@ class Config extends Component {
this.state.sapMcastAddr,
this.state.sapInterval,
this.state.mdnsEnabled)
.then(response => toast.success('Config updated, daemon restart ...'));
.then(response => toast.success('Applying new configuration ...'));
}
render() {