Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Development/nmos-cpp-node/node_implementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr
auto connection_sender = nmos::make_connection_events_websocket_sender(sender_id, device_id, source_id, model.settings);
connection_sender.data[nmos::fields::endpoint_active][nmos::fields::master_enable] = connection_sender.data[nmos::fields::endpoint_staged][nmos::fields::master_enable] = value::boolean(true);
resolve_auto(sender, connection_sender, connection_sender.data[nmos::fields::endpoint_active][nmos::fields::transport_params]);
nmos::set_resource_subscription(sender, nmos::fields::master_enable(connection_sender.data[nmos::fields::endpoint_active]), {}, nmos::tai_now());
nmos::set_resource_subscription(model.node_resources, sender, nmos::fields::master_enable(connection_sender.data[nmos::fields::endpoint_active]), {}, nmos::tai_now());

if (!insert_resource_after(delay_millis, model.node_resources, std::move(source), gate)) throw node_implementation_init_exception();
if (!insert_resource_after(delay_millis, model.node_resources, std::move(flow), gate)) throw node_implementation_init_exception();
Expand Down
4 changes: 2 additions & 2 deletions Development/nmos/activation_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,12 @@ namespace nmos
}
}

modify_resource(resources, id_type.first, [&response_activation](nmos::resource& resource)
modify_resource(resources, id_type.first, [&resources, &response_activation](nmos::resource& resource)
{
auto& staged = nmos::fields::endpoint_staged(resource.data);
auto& staged_activation = staged[nmos::fields::activation];

resource.data[nmos::fields::version] = web::json::value::string(nmos::make_version());
resource.data[nmos::fields::version] = value::string(nmos::make_version(nmos::strictly_increasing_update(resources)));

// "For immediate activations, [the `mode` field] will be null in response to any subsequent GET requests."
staged_activation[nmos::fields::mode] = value::null();
Expand Down
20 changes: 11 additions & 9 deletions Development/nmos/api_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,8 +503,13 @@ namespace nmos
nmos::api_gate gate(gate_, req, parameters);

const auto received_time = req.headers().find(details::received_time);

const auto processing_dur = req.headers().end() != received_time
? bst::chrono::duration_cast<bst::chrono::microseconds>(nmos::tai_clock::now() - nmos::time_point_from_tai(nmos::parse_version(received_time->second))).count() / 1000.0
? bst::chrono::duration_cast<bst::chrono::microseconds>(
// processing_dur = now - received time
( tai_clock::time_point(tai_clock::duration(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count()))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain this? Doesn't the steady_clock have a different epoch than tai_clock?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tai_clock now uses the boost implementation. According to the note in https://github.com/sony/nmos-cpp/blob/master/Development/nmos/api_utils.cpp#L710-L711, on Windows, the boost version of time_point::now (system_clock::now) sometimes returns the same value after a small time increment. Therefore, we are using std::chrono::steady_clock::now() here.

- nmos::time_point_from_tai(nmos::parse_version(received_time->second)))
).count() / 1000.0
: 0.0;

// experimental extension, to add Server-Timing response header
Expand Down Expand Up @@ -707,15 +712,12 @@ namespace nmos
add_api_finally_handler(api_, hsts, gate);
auto api = [api_, &gate](web::http::http_request req) mutable
{
// hmm, in Windows, the boost version of the time_point::now sometimes returns the same value after a small time increment.
// This issue does not seem to happen in the std::chrono implementation.
#if defined(_WIN32) && defined (BST_THREAD_BOOST)
// calculate received_time using std::chrono
const auto now = tai_clock::time_point(tai_clock::duration(std::chrono::system_clock::now().time_since_epoch().count() + tai_clock::tai_offset().count()));
// hmm, in Windows, the boost version of time_point::now (system_clock::now) sometimes returns the same value after a small time increment.
// I guess the same could happen with the Boost version of steady_clock::now, since this issue does not seem to occur in the std::chrono implementation.
// So let's use std::chrono for both Windows and Linux.
const auto now = tai_clock::time_point(tai_clock::duration(std::chrono::steady_clock::now().time_since_epoch().count()));
req.headers().add(details::received_time, nmos::make_version(tai_from_time_point(now)));
#else
req.headers().add(details::received_time, nmos::make_version());
#endif

slog::log<slog::severities::too_much_info>(gate, SLOG_FLF)
<< stash_remote_address(req.remote_address())
<< stash_http_method(req.method())
Expand Down
8 changes: 4 additions & 4 deletions Development/nmos/channelmapping_activation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ namespace nmos

if (!source_id_or_null.is_null())
{
nmos::modify_resource(model.node_resources, source_id_or_null.as_string(), [&activation_time](nmos::resource& source)
nmos::modify_resource(model.node_resources, source_id_or_null.as_string(), [&resources = model.node_resources, &activation_time](nmos::resource& source)
{
nmos::set_resource_version(source, activation_time);
nmos::set_resource_version(resources, source, activation_time);
});
}

Expand Down Expand Up @@ -188,9 +188,9 @@ namespace nmos

for (auto device = devices.first; devices.second != device; ++device)
{
nmos::modify_resource(model.node_resources, device->id, [&activation_time](nmos::resource& source)
nmos::modify_resource(model.node_resources, device->id, [&resources = model.node_resources, &activation_time](nmos::resource& source)
{
nmos::set_resource_version(source, activation_time);
nmos::set_resource_version(resources, source, activation_time);
});
}
}
Expand Down
5 changes: 2 additions & 3 deletions Development/nmos/channelmapping_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,14 +558,13 @@ namespace nmos

// Update the IS-04 source or device after the active map is changed in any way
// (This function should be called after nmos::set_channelmapping_output_active.)
void set_resource_version(nmos::resource& node_resource, const nmos::tai& activation_time)
void set_resource_version(const nmos::resources& node_resources, nmos::resource& node_resource, const nmos::tai& activation_time)
{
using web::json::value;

auto& resource = node_resource;
const auto at = value::string(nmos::make_version(activation_time));

resource.data[nmos::fields::version] = at;
resource.data[nmos::fields::version] = value::string(nmos::make_version(nmos::strictly_increasing_update(node_resources, activation_time)));
}

web::http::experimental::listener::api_router make_unmounted_channelmapping_api(nmos::node_model& model, details::channelmapping_output_map_validator validate_merged, slog::base_gate& gate_)
Expand Down
2 changes: 1 addition & 1 deletion Development/nmos/channelmapping_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ namespace nmos

// Update the IS-04 source or device after the active map is changed in any way
// (This function should be called after nmos::set_channelmapping_output_active.)
void set_resource_version(nmos::resource& node_resource, const nmos::tai& activation_time);
void set_resource_version(const nmos::resources& node_resources, nmos::resource& node_resource, const nmos::tai& activation_time);

// Channel Mapping API implementation details
namespace details
Expand Down
6 changes: 3 additions & 3 deletions Development/nmos/connection_activation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ namespace nmos
{
// Update the IS-05 resource's /active endpoint

nmos::set_connection_resource_active(connection_resource, [&](web::json::value& endpoint_active)
nmos::set_connection_resource_active(model.connection_resources, connection_resource, [&](web::json::value& endpoint_active)
{
// the resolve_auto callback may throw exceptions, which will prevent activation in order that
// "if there is an error condition that means `auto` cannot be resolved, the active transport parameters
Expand All @@ -169,9 +169,9 @@ namespace nmos

// Update the IS-04 resource's subscription

nmos::modify_resource(model.node_resources, id_type.first, [&activation_time, &active, &connected_id](nmos::resource& resource)
nmos::modify_resource(model.node_resources, id_type.first, [&resources = model.node_resources, &activation_time, &active, &connected_id](nmos::resource& resource)
{
nmos::set_resource_subscription(resource, active, connected_id, activation_time);
nmos::set_resource_subscription(resources, resource, active, connected_id, activation_time);
});

// Synchronous notification that the active parameters for the specified (IS-04/IS-05) sender/connection_sender or receiver/connection_receiver have changed
Expand Down
13 changes: 6 additions & 7 deletions Development/nmos/connection_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,9 +555,9 @@ namespace nmos

// Finally, update the staged endpoint

modify_resource(resources, id_type.first, [&merged](nmos::resource& resource)
modify_resource(resources, id_type.first, [&resources, &merged](nmos::resource& resource)
{
resource.data[nmos::fields::version] = web::json::value::string(nmos::make_version());
resource.data[nmos::fields::version] = value::string(nmos::make_version(nmos::strictly_increasing_update(resources)));

nmos::fields::endpoint_staged(resource.data) = merged;
// In the case of an immediate activation, this is not yet a valid response
Expand Down Expand Up @@ -709,15 +709,15 @@ namespace nmos
}

// Activate an IS-05 sender or receiver by transitioning the 'staged' settings into the 'active' resource
void set_connection_resource_active(nmos::resource& connection_resource, std::function<void(web::json::value& endpoint_active)> resolve_auto, const nmos::tai& activation_time)
void set_connection_resource_active(const nmos::resources& connection_resources, nmos::resource& connection_resource, std::function<void(web::json::value& endpoint_active)> resolve_auto, const nmos::tai& activation_time)
{
using web::json::value;
using web::json::value_of;

auto& resource = connection_resource;
const auto at = value::string(nmos::make_version(activation_time));

resource.data[nmos::fields::version] = at;
resource.data[nmos::fields::version] = value::string(nmos::make_version(nmos::strictly_increasing_update(connection_resources, activation_time)));

auto& staged = nmos::fields::endpoint_staged(resource.data);
auto& staged_activation = staged[nmos::fields::activation];
Expand Down Expand Up @@ -776,13 +776,12 @@ namespace nmos

// Update the IS-04 sender or receiver after the active connection is changed in any way
// (This function should be called after nmos::set_connection_resource_active.)
void set_resource_subscription(nmos::resource& node_resource, bool active, const nmos::id& connected_id, const nmos::tai& activation_time)
void set_resource_subscription(const nmos::resources& node_resources, nmos::resource& node_resource, bool active, const nmos::id& connected_id, const nmos::tai& activation_time)
{
using web::json::value;
using web::json::value_of;

auto& resource = node_resource;
const auto at = value::string(nmos::make_version(activation_time));

// "The 'receiver_id' key MUST be set to `null` in all cases except where a unicast push-based Sender is configured to transmit to an NMOS Receiver, and the 'active' key is set to 'true'."
// "The 'sender_id' key MUST be set to `null` in all cases except where the Receiver is currently configured to receive from an NMOS Sender, and the 'active' key is set to 'true'.
Expand All @@ -792,7 +791,7 @@ namespace nmos
// "When the 'active' parameters of a Sender or Receiver are modified, or when a re-activation of the same parameters
// is performed, the 'version' attribute of the relevant IS-04 Sender or Receiver must be incremented."
// See https://specs.amwa.tv/is-05/releases/v1.0.0/docs/3.1._Interoperability_-_NMOS_IS-04.html#version-increments
resource.data[nmos::fields::version] = at;
resource.data[nmos::fields::version] = value::string(nmos::make_version(nmos::strictly_increasing_update(node_resources, activation_time)));

// Senders indicate the connected receiver_id, receivers indicate the connected sender_id
// (depending on the API version)
Expand Down
5 changes: 3 additions & 2 deletions Development/nmos/connection_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "cpprest/api_router.h"
#include "nmos/id.h"
#include "nmos/resources.h"

namespace slog
{
Expand Down Expand Up @@ -57,15 +58,15 @@ namespace nmos
// Functions for interaction between the Connection API implementation and the connection activation thread

// Activate an IS-05 sender or receiver by transitioning the 'staged' settings into the 'active' resource
void set_connection_resource_active(nmos::resource& connection_resource, std::function<void(web::json::value& endpoint_active)> resolve_auto, const nmos::tai& activation_time);
void set_connection_resource_active(const nmos::resources& connection_resources, nmos::resource& connection_resource, std::function<void(web::json::value& endpoint_active)> resolve_auto, const nmos::tai& activation_time);

// Clear any pending activation of an IS-05 sender or receiver
// (This function should not be called after nmos::set_connection_resource_active.)
void set_connection_resource_not_pending(nmos::resource& connection_resource);

// Update the IS-04 sender or receiver after the active connection is changed in any way
// (This function should be called after nmos::set_connection_resource_active.)
void set_resource_subscription(nmos::resource& node_resource, bool active, const nmos::id& connected_id, const nmos::tai& activation_time);
void set_resource_subscription(const nmos::resources& node_resources, nmos::resource& node_resource, bool active, const nmos::id& connected_id, const nmos::tai& activation_time);

// Helper functions for the Connection API callbacks

Expand Down
8 changes: 4 additions & 4 deletions Development/nmos/connection_events_activation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,9 @@ namespace nmos
{
using web::json::value;

const auto at = web::json::value::string(nmos::make_version(activation_time));
const auto at = value::string(nmos::make_version(activation_time));

connection_resource.data[nmos::fields::version] = at;
connection_resource.data[nmos::fields::version] = value::string(nmos::make_version(nmos::strictly_increasing_update(model.connection_resources, activation_time)));

auto& endpoint_active = nmos::fields::endpoint_active(connection_resource.data);
auto& active_activation = endpoint_active[nmos::fields::activation];
Expand All @@ -185,9 +185,9 @@ namespace nmos

// Update the IS-04 resource's subscription

nmos::modify_resource(model.node_resources, id_type.first, [&activation_time](nmos::resource& resource)
nmos::modify_resource(model.node_resources, id_type.first, [&resources = model.node_resources, &activation_time](nmos::resource& resource)
{
nmos::set_resource_subscription(resource, false, {}, activation_time);
nmos::set_resource_subscription(resources, resource, false, {}, activation_time);
});
}
};
Expand Down
5 changes: 3 additions & 2 deletions Development/nmos/lldp_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace nmos
const auto& interface_name = interface->second.name;

using web::json::value_of;
using web::json::value;

auto lock = model.write_lock();
auto& resources = model.node_resources;
Expand Down Expand Up @@ -55,9 +56,9 @@ namespace nmos
{
slog::log<slog::severities::more_info>(gate, SLOG_FLF) << "LLDP received - updating attached network device info for network interface " << interface->second.name;

nmos::modify_resource(resources, resource->id, [&interface_name, &attached_network_device](nmos::resource& resource)
nmos::modify_resource(resources, resource->id, [&resources, &interface_name, &attached_network_device](nmos::resource& resource)
{
resource.data[nmos::fields::version] = web::json::value::string(nmos::make_version());
resource.data[nmos::fields::version] = value::string(nmos::make_version(nmos::strictly_increasing_update(resources)));

auto& json_interfaces = nmos::fields::interfaces(resource.data);

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ The implementation is designed to be extended. Development is ongoing, following

Recent activity on the project (newest first):

- Added Network Time Protocol (NTP) support
- Added support for IS-14 NMOS Device Configuration
- Added support for BCP-008-01 Receiver Status Monitoring
- Added support for BCP-008-02 Sender Status Monitoring
Expand Down
Loading