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, "sap_interval": 30,
"mac_addr": "01:00:5e:01:00:01", "mac_addr": "01:00:5e:01:00:01",
"ip_addr": "127.0.0.1", "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: where:
@ -221,7 +222,7 @@ where:
> The specific multicast RTP address is the base address plus the source id number. > 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. > 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. > JSON number specifying the RTP port used by the sources.
> **ptp\_domain** > **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. > 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. > **_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> ### ### JSON PTP Config<a name="ptp-config"></a> ###
Example Example

View File

@ -36,7 +36,8 @@
using namespace boost::asio; 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; Config config;
std::ifstream jsonstream(filename); std::ifstream jsonstream(filename);
@ -104,12 +105,14 @@ std::shared_ptr<Config> Config::parse(const std::string& filename) {
} }
config.config_filename_ = filename; config.config_filename_ = filename;
config.need_restart_ = false; config.daemon_restart_ = false;
config.driver_restart_ = driver_restart;
return std::make_shared<Config>(config); return std::make_shared<Config>(config);
} }
bool Config::save(const Config& config, bool need_restart) { bool Config::save(const Config& config) {
if (*this != config) {
std::ofstream js(config_filename_); std::ofstream js(config_filename_);
if (!js) { if (!js) {
BOOST_LOG_TRIVIAL(fatal) BOOST_LOG_TRIVIAL(fatal)
@ -117,7 +120,28 @@ bool Config::save(const Config& config, bool need_restart) {
return false; return false;
} }
js << config_to_json(config); 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"; BOOST_LOG_TRIVIAL(info) << "Config:: file saved";
need_restart_ = need_restart; } else {
BOOST_LOG_TRIVIAL(info) << "Config:: unchanged";
}
return true; return true;
} }

View File

@ -27,9 +27,10 @@
class Config { class Config {
public: public:
/* save new config to json file */ /* 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 */ /* 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 */ /* attributes retrieved from config json */
uint16_t get_http_port() const { return http_port_; }; 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_; }; const std::string& get_mac_addr_str() const { return mac_str_; };
uint32_t get_ip_addr() const { return ip_addr_; }; uint32_t get_ip_addr() const { return ip_addr_; };
const std::string& get_ip_addr_str() const { return ip_str_; }; 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_; }; bool get_mdns_enabled() const { return mdns_enabled_; };
int get_interface_idx() { return interface_idx_; }; 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_http_port(uint16_t http_port) { http_port_ = http_port; };
void set_rtsp_port(uint16_t rtsp_port) { rtsp_port_ = rtsp_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_mdns_enabled(bool enabled) { mdns_enabled_ = enabled; };
void set_interface_idx(int index) { interface_idx_ = index; }; 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: private:
/* from json */ /* from json */
@ -131,6 +165,7 @@ class Config {
std::string status_file_{"./status.json"}; std::string status_file_{"./status.json"};
std::string interface_name_{"eth0"}; std::string interface_name_{"eth0"};
bool mdns_enabled_{true}; bool mdns_enabled_{true};
std::string ptp_status_script_;
/* set during init */ /* set during init */
std::array<uint8_t, 6> mac_addr_{0, 0, 0, 0, 0, 0}; std::array<uint8_t, 6> mac_addr_{0, 0, 0, 0, 0, 0};
@ -140,8 +175,10 @@ class Config {
int interface_idx_; int interface_idx_;
std::string config_filename_; std::string config_filename_;
/* reconfig needs driver restart */
bool driver_restart_{true};
/* reconfig needs daemon restart */ /* reconfig needs daemon restart */
bool need_restart_{false}; bool daemon_restart_{false};
}; };
#endif #endif

View File

@ -16,6 +16,7 @@
"syslog_proto": "none", "syslog_proto": "none",
"syslog_server": "255.255.255.254:1234", "syslog_server": "255.255.255.254:1234",
"status_file": "./status.json", "status_file": "./status.json",
"interface_name": "lo",
"mdns_enabled": true, "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; return true;
} }
bool DriverHandler::terminate() { bool DriverHandler::terminate(const Config& /* config */) {
if (running_) { if (running_) {
running_ = false; running_ = false;
client_u2k_.terminate(); client_u2k_.terminate();

View File

@ -40,10 +40,10 @@ class DriverHandler {
DriverHandler(){}; DriverHandler(){};
DriverHandler(const DriverHandler&) = delete; DriverHandler(const DriverHandler&) = delete;
DriverHandler& operator=(const DriverHandler&) = delete; DriverHandler& operator=(const DriverHandler&) = delete;
virtual ~DriverHandler() { terminate(); }; virtual ~DriverHandler(){};
virtual bool init(const Config& config); virtual bool init(const Config& config);
virtual bool terminate(); virtual bool terminate(const Config& config);
protected: protected:
virtual void send_command(enum MT_ALSA_msg_id id, 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.ui8Domain = config.get_ptp_domain();
ptp_config.ui8DSCP = config.get_ptp_dscp(); ptp_config.ui8DSCP = config.get_ptp_dscp();
bool res = hello() || start() || reset() || if (hello())
return false;
bool res(false);
if (config.get_driver_restart()) {
res = start() || reset() ||
set_interface_name(config.get_interface_name()) || set_interface_name(config.get_interface_name()) ||
set_ptp_config(ptp_config) || set_ptp_config(ptp_config) ||
set_tic_frame_size_at_1fs(config.get_tic_frame_size_at_1fs()) || set_tic_frame_size_at_1fs(config.get_tic_frame_size_at_1fs()) ||
set_playout_delay(config.get_playout_delay()) || set_playout_delay(config.get_playout_delay()) ||
set_max_tic_frame_size(config.get_max_tic_frame_size()); set_max_tic_frame_size(config.get_max_tic_frame_size());
}
return !res; return !res;
} }
bool DriverManager::terminate() { bool DriverManager::terminate(const Config& config) {
if (config.get_driver_restart()) {
stop(); stop();
}
bye(); bye();
return DriverHandler::terminate(); return DriverHandler::terminate(config);
} }
std::error_code DriverManager::hello() { std::error_code DriverManager::hello() {

View File

@ -33,7 +33,7 @@ class DriverManager : public DriverHandler {
// driver interface // driver interface
bool init(const Config& config) override; 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 ping(); // unused, return error
std::error_code set_ptp_config(const TPTPConfig& config); 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) { svr_.Post("/api/config", [this](const Request& req, Response& res) {
try { try {
Config config = json_to_config(req.body, *config_); 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)) { if (!config_->save(config)) {
set_error(500, "failed to save config", res); set_error(500, "failed to save config", res);
return; return;
@ -153,7 +177,7 @@ bool HttpServer::init() {
Config config(*config_); Config config(*config_);
config.set_ptp_domain(ptpConfig.domain); config.set_ptp_domain(ptpConfig.domain);
config.set_ptp_dscp(ptpConfig.dscp); config.set_ptp_dscp(ptpConfig.dscp);
if (!config_->save(config, false)) { if (!config_->save(config)) {
set_error(500, "failed to save config", res); set_error(500, "failed to save config", res);
return; return;
} }

View File

@ -115,7 +115,6 @@ int get_interface_index(const std::string& interface_name) {
return ifr.ifr_ifindex; return ifr.ifr_ifindex;
} }
std::pair<std::array<uint8_t, 6>, std::string> get_mac_from_arp_cache( std::pair<std::array<uint8_t, 6>, std::string> get_mac_from_arp_cache(
const std::string& interface_name, const std::string& interface_name,
const std::string& ip) { const std::string& ip) {
@ -155,7 +154,6 @@ std::pair<std::array<uint8_t, 6>, std::string> get_mac_from_arp_cache(
return {mac, ""}; return {mac, ""};
} }
bool ping(const std::string& ip) { bool ping(const std::string& ip) {
static uint16_t sequence_number(0); static uint16_t sequence_number(0);
uint16_t identifier(0xABAB); uint16_t identifier(0xABAB);
@ -182,7 +180,6 @@ bool ping(const std::string& ip) {
return true; return true;
} }
bool echo_try_connect(const std::string& ip) { bool echo_try_connect(const std::string& ip) {
ip::tcp::iostream s; ip::tcp::iostream s;
BOOST_LOG_TRIVIAL(debug) << "echo_connect:: connecting to " << ip; 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 \"ip_addr\": \"" << escape_json(config.get_ip_addr_str()) << "\""
<< ",\n \"node_id\": \"" << escape_json(get_node_id(config.get_ip_addr())) << ",\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"; << "\n}\n";
return ss.str(); return ss.str();
} }
@ -320,6 +322,9 @@ Config json_to_config_(std::istream& js, Config& config) {
} else if (key == "syslog_server") { } else if (key == "syslog_server") {
config.set_syslog_server( config.set_syslog_server(
remove_undesired_chars(val.get_value<std::string>())); 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") { } else if (key == "mac_addr" || key == "ip_addr" || key == "node_id") {
/* ignored */ /* ignored */
} else { } else {

View File

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

View File

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

View File

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

View File

@ -15,7 +15,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "utils.hpp" #include "utils.hpp"
#include "rtsp_server.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 #define CPPHTTPLIB_PAYLOAD_MAX_LENGTH 4096 // max for SDP file
#include <stdlib.h>
#include <httplib.h> #include <httplib.h>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
@ -513,13 +514,16 @@ std::error_code SessionManager::add_source(const StreamSource& source) {
info.stream.m_ui8DestMAC); info.stream.m_ui8DestMAC);
info.stream.m_byTTL = source.ttl; info.stream.m_byTTL = source.ttl;
} else { } 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()); ip::address_v4(info.stream.m_ui32DestIP).to_string());
int retry = 3; int retry = 3;
while (!mac_addr.second.length() && retry--) { while (!mac_addr.second.length() && retry--) {
// if not in cache already try to populate the MAC cache // if not in cache already try to populate the MAC cache
(void)echo_try_connect(ip::address_v4(info.stream.m_ui32DestIP).to_string()); (void)echo_try_connect(
mac_addr = get_mac_from_arp_cache(config_->get_interface_name(), 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()); ip::address_v4(info.stream.m_ui32DestIP).to_string());
} }
if (!mac_addr.second.length()) { 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)) { if (IN_MULTICAST(info.stream.m_ui32DestIP)) {
ss << "/" << static_cast<unsigned>(info.stream.m_byTTL); ss << "/" << static_cast<unsigned>(info.stream.m_byTTL);
} }
ss << "\na=rtpmap:" << static_cast<unsigned>(info.stream.m_byPayloadType) << " " ss << "\na=rtpmap:" << static_cast<unsigned>(info.stream.m_byPayloadType)
<< info.stream.m_cCodec << "/" << sample_rate << "/" << " " << info.stream.m_cCodec << "/" << sample_rate << "/"
<< static_cast<unsigned>(info.stream.m_byNbOfChannels) << "\n" << static_cast<unsigned>(info.stream.m_byNbOfChannels) << "\n"
<< "a=sync-time:0\n" << "a=sync-time:0\n"
<< "a=framecount:" << info.stream.m_ui32MaxSamplesPerPacket << "\n" << "a=framecount:" << info.stream.m_ui32MaxSamplesPerPacket << "\n"
@ -902,6 +906,19 @@ std::error_code SessionManager::get_sink_status(
return ret; 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) { std::error_code SessionManager::set_ptp_config(const PTPConfig& config) {
TPTPConfig ptp_config; TPTPConfig ptp_config;
ptp_config.ui8Domain = config.domain; ptp_config.ui8Domain = config.domain;
@ -1002,11 +1019,33 @@ void SessionManager::on_update_sources() {
g_session_version++; g_session_version++;
} }
void SessionManager::on_ptp_status_locked() const { void SessionManager::on_ptp_status_changed(const std::string& status) const {
if (status == "locked") {
// set sample rate, this may require seconds // set sample rate, this may require seconds
(void)driver_->set_sample_rate(driver_->get_current_sample_rate()); (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; using namespace std::chrono;
using second_t = duration<double, std::ratio<1> >; using second_t = duration<double, std::ratio<1> >;
@ -1043,7 +1082,7 @@ bool SessionManager::worker() {
pui64GMID[5], pui64GMID[6], pui64GMID[7]); pui64GMID[5], pui64GMID[6], pui64GMID[7]);
bool ptp_changed_gmid = false; bool ptp_changed_gmid = false;
bool ptp_changed_to_locked = false; std::string ptp_status_changed_to;
// update PTP clock status // update PTP clock status
ptp_mutex_.lock(); ptp_mutex_.lock();
// update status // update status
@ -1069,15 +1108,13 @@ bool SessionManager::worker() {
BOOST_LOG_TRIVIAL(info) BOOST_LOG_TRIVIAL(info)
<< "session_manager:: new PTP clock status " << new_ptp_status; << "session_manager:: new PTP clock status " << new_ptp_status;
ptp_status_.status = new_ptp_status; ptp_status_.status = new_ptp_status;
if (new_ptp_status == "locked") { ptp_status_changed_to = new_ptp_status;
ptp_changed_to_locked = true;
}
} }
// end update PTP clock status // end update PTP clock status
ptp_mutex_.unlock(); ptp_mutex_.unlock();
if (ptp_changed_to_locked) { if (!ptp_status_changed_to.empty()) {
on_ptp_status_locked(); on_ptp_status_changed(ptp_status_changed_to);
} }
if (ptp_changed_gmid || if (ptp_changed_gmid ||

View File

@ -151,6 +151,8 @@ class SessionManager {
uint8_t get_sink_id(const std::string& name) const; uint8_t get_sink_id(const std::string& name) const;
std::error_code set_ptp_config(const PTPConfig& config); 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_config(PTPConfig& config) const;
void get_ptp_status(PTPStatus& status) 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_add_sink(const StreamSink& sink, const StreamInfo& info);
void on_remove_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(); void on_update_sources();

View File

@ -20,5 +20,6 @@
"mdns_enabled": true, "mdns_enabled": true,
"mac_addr": "00:00:00:00:00:00", "mac_addr": "00:00:00:00:00:00",
"ip_addr": "127.0.0.1", "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_proto = pt.get<std::string>("syslog_proto");
auto syslog_server = pt.get<std::string>("syslog_server"); auto syslog_server = pt.get<std::string>("syslog_server");
auto status_file = pt.get<std::string>("status_file"); 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 interface_name = pt.get<std::string>("interface_name");
auto mac_addr = pt.get<std::string>("mac_addr"); auto mac_addr = pt.get<std::string>("mac_addr");
auto ip_addr = pt.get<std::string>("ip_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(interface_name == "lo", "config as excepcted");
BOOST_CHECK_MESSAGE(mac_addr == "00:00:00:00:00:00", "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(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) { BOOST_AUTO_TEST_CASE(get_ptp_status) {

View File

@ -20,5 +20,6 @@
"mdns_enabled": false, "mdns_enabled": false,
"mac_addr": "00:00:00:00:00:00", "mac_addr": "00:00:00:00:00:00",
"ip_addr": "127.0.0.1", "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.sapMcastAddr,
this.state.sapInterval, this.state.sapInterval,
this.state.mdnsEnabled) this.state.mdnsEnabled)
.then(response => toast.success('Config updated, daemon restart ...')); .then(response => toast.success('Applying new configuration ...'));
} }
render() { render() {