Skip to content
Open
Changes from all 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
213 changes: 201 additions & 12 deletions Development/nmos-cpp-node/node_implementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,149 @@
nmos::nc::counter late_packet_counter;
};
std::vector<nic_packet_counter> nic_packet_counters;

// Example of sender control class descriptors. Used below for setting up a sender control class
void make_sender_control_descriptors(nmos::experimental::control_protocol_state & control_protocol_state, nmos::nc_class_id snd_class_id)
{
using web::json::value;
using web::json::value_of;

// Datatype description for an object within an object
auto make_struct_datatype = [](const std::vector<std::tuple<utility::string_t,utility::string_t,utility::string_t, bool>>& obj_desc,
const utility::string_t& descriptor, const utility::string_t& type_name) {
using web::json::value;
auto fields = value::array();
for ( auto obj : obj_desc ) {
auto data = nmos::nc::details::make_field_descriptor(std::get<0>(obj), std::get<1>(obj), std::get<2>(obj), true, std::get<3>(obj), value::null());
web::json::push_back(fields, std::move(data));
}
auto ret = nmos::nc::details::make_datatype_descriptor_struct(descriptor, type_name, fields, value::null());
return ret;
};

std::vector<std::tuple<utility::string_t,utility::string_t,utility::string_t, bool>> subscription_struct_fields {
// description, name, type_name, is_sequence
{U("active"), U("active"), U("NcBoolean"), false},
{U("receiver_id"), U("receiver_id"), U("NcUuid"), false}
};
auto subscription_data_type = make_struct_datatype(subscription_struct_fields, U("SubscriptionType"), U("SubscriptionType"));
control_protocol_state.insert(std::move(nmos::experimental::datatype_descriptor{ subscription_data_type }));

std::vector<std::tuple<utility::string_t, utility::string_t, utility::string_t, bool>> key_value_struct_fields{
// description, name, type_name, is_sequence
{U("key"), U("key"), U("NcString"), false},
{U("value"), U("value"), U("NcString"), true}
};
auto key_value_data_type = make_struct_datatype(key_value_struct_fields, U("KeyValueStruct"), U("KeyValueStruct"));
control_protocol_state.insert(std::move(nmos::experimental::datatype_descriptor{ key_value_data_type }));

const web::json::field_as_value caps_property{ U("caps") };
const web::json::field_as_string description_property{ U("description") };
const web::json::field_as_string device_id_property{ U("device_id") };
const web::json::field_as_string flow_id_property{ U("flow_id") };
const web::json::field_as_string uuid_property{ U("resource_id") };
const web::json::field_as_array interface_bindings_property{ U("interface_bindings") };
const web::json::field_as_string label_property{ U("label") };
const web::json::field_as_string manifest_href_property{ U("manifest_href") };
const web::json::field_as_array subscription_property{ U("subscription") };
const web::json::field_as_value tags_property{ U("tags") };
const web::json::field_as_string transport_property{ U("transport") };
const web::json::field<nmos::tai> version_property{ U("version") };

// Define property descriptors
std::vector<web::json::value> snd_control_property_descriptors = {
// Property descriptor for required fields
nmos::experimental::make_control_class_property_descriptor(U("description"), { 3, 1 }, description_property, U("NcString"), true, false, false, false, web::json::value::null()),
nmos::experimental::make_control_class_property_descriptor(U("resource_id"), { 3, 2 }, uuid_property, U("NcUuid"), true, false, false, false, web::json::value::null()),
nmos::experimental::make_control_class_property_descriptor(U("label"), { 3, 3 }, label_property, U("NcString"), true, false, false, false, web::json::value::null()),
nmos::experimental::make_control_class_property_descriptor(U("tags"), { 3, 4 }, tags_property, U("KeyValueStruct"), true, false, true, false, web::json::value::null()),
nmos::experimental::make_control_class_property_descriptor(U("version"), { 3, 5 }, version_property, U("NcVersionCode"), true, false, false, false, web::json::value::null()),

// Property descriptor for optional fields
nmos::experimental::make_control_class_property_descriptor(U("caps"), { 3, 6 }, caps_property, U("KeyValueStruct"), true, true, true, false, web::json::value::null()),
nmos::experimental::make_control_class_property_descriptor(U("description"), { 3, 7 }, device_id_property, U("NcUuid"), true, true, false, false, web::json::value::null()),
nmos::experimental::make_control_class_property_descriptor(U("flow_id"), { 3, 8 }, flow_id_property, U("NcUuid"), true, true, false, false, web::json::value::null()),
nmos::experimental::make_control_class_property_descriptor(U("interface_bindings"), { 3, 9 }, interface_bindings_property, U("NcString"), true, false, true, false, web::json::value::null()),
nmos::experimental::make_control_class_property_descriptor(U("manifest_href"), { 3, 10 }, manifest_href_property, U("NcUri"), true, true, false, false, web::json::value::null()),
nmos::experimental::make_control_class_property_descriptor(U("subscription"), { 3, 11 }, subscription_property, U("SubscriptionType"), true, true, false, false, web::json::value::null()),
nmos::experimental::make_control_class_property_descriptor(U("transport"), { 3, 12 }, transport_property, U("NcString"), true, true, false, false, web::json::value::null())
};
// method and event descriptors are defined by defaults in the function prototype, so only need to pass the property descriptors
utility::string_t descriptor_description = utility::string_t(U("SenderControl")) + utility::string_t(U("Sender control class descriptor"));
auto sender_control_class_descriptor =
nmos::experimental::make_control_class_descriptor(descriptor_description,
snd_class_id, U("SenderControl"),
snd_control_property_descriptors);

// Insert class descriptor into the nmos-cpp framework
control_protocol_state.insert(std::move(sender_control_class_descriptor));
}

// Example of an sender control class
static nmos::control_protocol_resource make_sender_control(const nmos::nc_class_id& snd_class_id,
const web::json::value& sender_data,
const nmos::nc_oid& oid,
const utility::string_t& role,
const nmos::nc_oid& parent_oid,
const web::json::value touchpoint,
slog::base_gate & gate)
{
using web::json::value;
using web::json::value_of;

auto make_key_value_array = [](const value& object)
{
auto key_value_array = value::array();

for (auto iter = object.as_object().begin(); iter != object.as_object().end(); iter++)
{
web::json::push_back(key_value_array, web::json::value_of({ { U("key"), (*iter).first}, {U("value"), (*iter).second } }));
}
return key_value_array;
};

const web::json::field_as_array caps_property{ U("caps") };
const web::json::field_as_string description_property{ U("description") };
const web::json::field_as_string device_id_property{ U("device_id") };
const web::json::field_as_string flow_id_property{ U("flow_id") };
const web::json::field_as_string uuid_property{ U("resource_id") };
const web::json::field_as_array interface_bindings_property{ U("interface_bindings") };
const web::json::field_as_string label_property{ U("label") };
const web::json::field_as_string manifest_href_property{ U("manifest_href") };
const web::json::field_as_array subscription_property{ U("subscription") };
const web::json::field_as_value tags_property{ U("tags") };
const web::json::field_as_string transport_property{ U("transport") };
const web::json::field<nmos::tai> version_property{ U("version") };

auto snd_name = U("SenderControl");

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04: build and test (install mdns: true, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: true)

unused variable ‘snd_name’ [-Wunused-variable]

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04: build and test (install mdns: true, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: true)

unused variable ‘snd_name’ [-Wunused-variable]

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: true)

unused variable ‘snd_name’ [-Wunused-variable]

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: true)

unused variable ‘snd_name’ [-Wunused-variable]

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / windows-2022: build and test (install mdns: false, use conan: true, force cpprest asio: true, dns-sd mode: multicast, enable_authorization: false)

'snd_name': local variable is initialized but not referenced

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / windows-2022: build and test (install mdns: false, use conan: true, force cpprest asio: true, dns-sd mode: multicast, enable_authorization: false)

'snd_name': local variable is initialized but not referenced

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: false)

unused variable ‘snd_name’ [-Wunused-variable]

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: false)

unused variable ‘snd_name’ [-Wunused-variable]

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / windows-2022: build and test (install mdns: false, use conan: true, force cpprest asio: true, dns-sd mode: multicast, enable_authorization: true)

'snd_name': local variable is initialized but not referenced

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / windows-2022: build and test (install mdns: false, use conan: true, force cpprest asio: true, dns-sd mode: multicast, enable_authorization: true)

'snd_name': local variable is initialized but not referenced

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: true)

unused variable ‘snd_name’ [-Wunused-variable]

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: true)

unused variable ‘snd_name’ [-Wunused-variable]

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / windows-2022: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: true)

'snd_name': local variable is initialized but not referenced

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / windows-2022: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: true)

'snd_name': local variable is initialized but not referenced

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: unicast, enable_authorization: true)

unused variable ‘snd_name’ [-Wunused-variable]

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: unicast, enable_authorization: true)

unused variable ‘snd_name’ [-Wunused-variable]

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / windows-2022: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: false)

'snd_name': local variable is initialized but not referenced

Check warning on line 320 in Development/nmos-cpp-node/node_implementation.cpp

View workflow job for this annotation

GitHub Actions / windows-2022: build and test (install mdns: false, use conan: true, force cpprest asio: false, dns-sd mode: multicast, enable_authorization: false)

'snd_name': local variable is initialized but not referenced
// define a function for instantiating object instances of the class
auto data = nmos::nc::details::make_worker(snd_class_id, oid,
true,
parent_oid,
role,
web::json::value(role),
U("Sender resource data"),
touchpoint,
web::json::value::null(),
true);

// Required
data[description_property] = sender_data.at(U("description"));
data[uuid_property] = sender_data.at(U("id"));
data[label_property] = sender_data.at(U("label"));
data[tags_property] = make_key_value_array(sender_data.at(U("tags")));
data[version_property] = sender_data.at(U("version"));
// Optional
data[caps_property] = sender_data.has_field(U("caps")) ? make_key_value_array(sender_data.at(U("caps"))) : web::json::value::array();
data[device_id_property] = sender_data.has_field(U("device_id")) ? sender_data.at(U("device_id")) : web::json::value::null();
data[flow_id_property] = sender_data.has_field(U("flow_id")) ? sender_data.at(U("flow_id")) : web::json::value::null();
data[interface_bindings_property] = sender_data.has_field(U("interface_bindings")) ? sender_data.at(U("interface_bindings")) : web::json::value::array();
data[manifest_href_property] = sender_data.has_field(U("manifest_href")) ? sender_data.at(U("manifest_href")) : web::json::value::null();
data[subscription_property] = sender_data.has_field(U("subscription")) ? sender_data.at(U("subscription")) : web::json::value::null();
data[transport_property] = sender_data.has_field(U("transport")) ? sender_data.at(U("transport")) : web::json::value::null();

return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true };
}
}

// forward declarations for node_implementation_thread
Expand Down Expand Up @@ -1212,6 +1355,10 @@
return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true };
};

// example audio sender control descriptors
auto sender_control_class_id = nmos::nc::make_class_id(nmos::nc_worker_class_id, 0, { 5 });
impl::make_sender_control_descriptors(control_protocol_state, sender_control_class_id);

// example root block
auto root_block = nmos::make_root_block();

Expand Down Expand Up @@ -1275,12 +1422,12 @@
// making an object rebuildable allows read only properties to be modified by the Configuration API in Rebuild mode
nmos::make_rebuildable(example_control);

const auto receivers_block_oid = ++oid;
auto receivers_block = nmos::make_block(receivers_block_oid, nmos::root_block_oid, U("receivers"), U("Receiver Monitors"), U("Receiver Monitors"));
const auto receiver_monitors_block_oid = ++oid;
auto receiver_monitors_block = nmos::make_block(receiver_monitors_block_oid, nmos::root_block_oid, U("receiver-monitors"), U("Receiver Monitors"), U("Receiver Monitors"));
// making a block rebuildable allows block members to be added or removed by the Configuration API in Rebuild mode
nmos::make_rebuildable(receivers_block);
nmos::make_rebuildable(receiver_monitors_block);
// restrict the allowed classes for members of this block
nmos::set_block_allowed_member_classes(receivers_block, {nmos::nc_receiver_monitor_class_id});
nmos::set_block_allowed_member_classes(receiver_monitors_block, {nmos::nc_receiver_monitor_class_id});

// example receiver-monitor(s)
{
Expand All @@ -1294,15 +1441,22 @@
utility::ostringstream_t role;
role << U("receiver-monitor-") << ++count;
const auto& receiver = nmos::find_resource(model.node_resources, receiver_id);
auto receiver_monitor = nmos::make_receiver_monitor(++oid, true, receivers_block_oid, role.str(), nmos::fields::label(receiver->data), nmos::fields::description(receiver->data), value_of({ { nmos::nc::details::make_touchpoint_nmos({nmos::ncp_touchpoint_resource_types::receiver, receiver_id}) } }));
auto receiver_monitor = nmos::make_receiver_monitor(++oid, true, receiver_monitors_block_oid, role.str(), nmos::fields::label(receiver->data), nmos::fields::description(receiver->data), value_of({ { nmos::nc::details::make_touchpoint_nmos({nmos::ncp_touchpoint_resource_types::receiver, receiver_id}) } }));
// optionally indicate dependencies within the device model
nmos::set_object_dependency_paths(receiver_monitor, {{U("root"), U("receivers")}});
nmos::set_object_dependency_paths(receiver_monitor, {{U("root"), U("receiver-monitors")}});
// add receiver-monitor to receivers-block
nmos::nc::push_back(receivers_block, receiver_monitor);
nmos::nc::push_back(receiver_monitors_block, receiver_monitor);
}
}
}

const auto sender_monitors_block_oid = ++oid;
auto sender_monitors_block = nmos::make_block(sender_monitors_block_oid, nmos::root_block_oid, U("sender-monitors"), U("Sender Monitors"), U("Sender Monitors"));
// making a block rebuildable allows block members to be added or removed by the Configuration API in Rebuild mode
nmos::make_rebuildable(sender_monitors_block);
// restrict the allowed classes for members of this block
nmos::set_block_allowed_member_classes(sender_monitors_block, { nmos::nc_sender_monitor_class_id });

// example sender-monitor(s)
{
int count = 0;
Expand All @@ -1315,19 +1469,54 @@
utility::ostringstream_t role;
role << U("sender-monitor-") << ++count;
const auto& sender = nmos::find_resource(model.node_resources, sender_id);
const auto sender_monitor = nmos::make_sender_monitor(++oid, true, nmos::root_block_oid, role.str(), nmos::fields::label(sender->data), nmos::fields::description(sender->data), value_of({ { nmos::nc::details::make_touchpoint_nmos({nmos::ncp_touchpoint_resource_types::sender, sender_id}) } }));

auto sender_monitor = nmos::make_sender_monitor(++oid, true, sender_monitors_block_oid, role.str(), nmos::fields::label(sender->data), nmos::fields::description(sender->data), value_of({ { nmos::nc::details::make_touchpoint_nmos({nmos::ncp_touchpoint_resource_types::sender, sender_id}) } }));
// optionally indicate dependencies within the device model
nmos::set_object_dependency_paths(sender_monitor, { {U("root"), U("sender-monitors")} });
// add sender-monitor to root-block
nmos::nc::push_back(root_block, sender_monitor);
nmos::nc::push_back(sender_monitors_block, sender_monitor);
}
}
}

const auto sender_controls_block_oid = ++oid;
auto sender_controls_block = nmos::make_block(sender_controls_block_oid, nmos::root_block_oid, U("sender-controls"), U("Sender Controls"), U("Sender Controls"));

// example audio sender control(s)
{
int count = 0;
for (int index = 0; index < how_many; ++index)
{
for (const auto& port : rtp_receiver_ports)
{
// only create audio sender controls for audio senders
//if (impl::ports::audio != port) continue;

const auto sender_id = impl::make_id(seed_id, nmos::types::sender, port, index);

utility::ostringstream_t role;
role << U("sender-control-") << ++count;
const auto& sender = nmos::find_resource(model.node_resources, sender_id);
auto sender_control = impl::make_sender_control(sender_control_class_id,
sender->data,
++oid, role.str(),
sender_controls_block_oid,
value_of({ { nmos::nc::details::make_touchpoint_nmos({nmos::ncp_touchpoint_resource_types::sender, sender_id}) } }),
gate);
// add receiver-monitor to receivers-block
nmos::nc::push_back(sender_controls_block, sender_control);
}
}
}

// example temperature-sensor
const auto temperature_sensor = make_temperature_sensor(++oid, nmos::root_block_oid, U("temperature-sensor"), U("Temperature Sensor"), U("Temperature Sensor block"), value::null(), value::null(), 0.0, U("Celsius"));

// add receivers-block to root-block
nmos::nc::push_back(root_block, receivers_block);
// add receiver-monitors-block to root-block
nmos::nc::push_back(root_block, receiver_monitors_block);
// add sender-monitors-block to root-block
nmos::nc::push_back(root_block, sender_monitors_block);
// add sender-controls-block to root-block
nmos::nc::push_back(root_block, sender_controls_block);
// add temperature-sensor to root-block
nmos::nc::push_back(root_block, temperature_sensor);
// add example-control to root-block
Expand Down
Loading