Skip to content

Commit 0059a0b

Browse files
maweitMartin Weishartlo-simon
authored
Add sender control example to node implementation (#478)
* Add sender control example to node implementation * Update Development/nmos-cpp-node/node_implementation.cpp Co-authored-by: Simon Lo <[email protected]> * Update Development/nmos-cpp-node/node_implementation.cpp Co-authored-by: Simon Lo <[email protected]> * Update Development/nmos-cpp-node/node_implementation.cpp Co-authored-by: Simon Lo <[email protected]> * Update Development/nmos-cpp-node/node_implementation.cpp Co-authored-by: Simon Lo <[email protected]> * Update Development/nmos-cpp-node/node_implementation.cpp Co-authored-by: Simon Lo <[email protected]> * Update Development/nmos-cpp-node/node_implementation.cpp Co-authored-by: Simon Lo <[email protected]> * Update Development/nmos-cpp-node/node_implementation.cpp Co-authored-by: Simon Lo <[email protected]> * Update Development/nmos-cpp-node/node_implementation.cpp Co-authored-by: Simon Lo <[email protected]> * Update Development/nmos-cpp-node/node_implementation.cpp Co-authored-by: Simon Lo <[email protected]> * Remove doubled example sender-monitor code from node implementation Removed doubled example sender-monitor implementation code. --------- Co-authored-by: Martin Weishart <[email protected]> Co-authored-by: Simon Lo <[email protected]>
1 parent 683299a commit 0059a0b

File tree

1 file changed

+194
-13
lines changed

1 file changed

+194
-13
lines changed

Development/nmos-cpp-node/node_implementation.cpp

Lines changed: 194 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,143 @@ namespace impl
203203
nmos::nc::counter late_packet_counter;
204204
};
205205
std::vector<nic_packet_counter> nic_packet_counters;
206+
207+
// Example of sender control class descriptors. Used below for setting up a sender control class
208+
void make_sender_control_descriptors(nmos::experimental::control_protocol_state & control_protocol_state, nmos::nc_class_id snd_class_id)
209+
{
210+
using web::json::value;
211+
using web::json::value_of;
212+
213+
// Datatype description for an object within an object
214+
215+
auto make_struct_datatype = [](const std::vector<std::tuple<utility::string_t,utility::string_t,utility::string_t, bool>>& obj_desc,
216+
const utility::string_t& descriptor, const utility::string_t& type_name) {
217+
using web::json::value;
218+
auto fields = value::array();
219+
for ( auto obj : obj_desc ) {
220+
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());
221+
web::json::push_back(fields, std::move(data));
222+
}
223+
auto ret = nmos::nc::details::make_datatype_descriptor_struct(descriptor, type_name, fields, value::null());
224+
return ret;
225+
};
226+
std::vector<std::tuple<utility::string_t,utility::string_t,utility::string_t, bool>> subscription_struct_fields {
227+
// description, name, type_name, is_sequence
228+
{U("active"), U("active"), U("NcBoolean"), false},
229+
{U("receiver_id"), U("receiver_id"), U("NcUuid"), false}
230+
};
231+
auto subscription_data_type = make_struct_datatype(subscription_struct_fields, U("SubscriptionType"), U("SubscriptionType"));
232+
control_protocol_state.insert(std::move(nmos::experimental::datatype_descriptor{ subscription_data_type }));
233+
std::vector<std::tuple<utility::string_t, utility::string_t, utility::string_t, bool>> key_value_struct_fields{
234+
// description, name, type_name, is_sequence
235+
{U("key"), U("key"), U("NcString"), false},
236+
{U("value"), U("value"), U("NcString"), true}
237+
};
238+
auto key_value_data_type = make_struct_datatype(key_value_struct_fields, U("KeyValueStruct"), U("KeyValueStruct"));
239+
control_protocol_state.insert(std::move(nmos::experimental::datatype_descriptor{ key_value_data_type }));
240+
241+
const web::json::field_as_value caps_property{ U("caps") };
242+
const web::json::field_as_string description_property{ U("description") };
243+
const web::json::field_as_string device_id_property{ U("device_id") };
244+
const web::json::field_as_string flow_id_property{ U("flow_id") };
245+
const web::json::field_as_string uuid_property{ U("resource_id") };
246+
const web::json::field_as_array interface_bindings_property{ U("interface_bindings") };
247+
const web::json::field_as_string label_property{ U("label") };
248+
const web::json::field_as_string manifest_href_property{ U("manifest_href") };
249+
const web::json::field_as_array subscription_property{ U("subscription") };
250+
const web::json::field_as_value tags_property{ U("tags") };
251+
const web::json::field_as_string transport_property{ U("transport") };
252+
const web::json::field<nmos::tai> version_property{ U("version") };
253+
254+
// Define property descriptors
255+
std::vector<web::json::value> snd_control_property_descriptors = {
256+
// Property descriptor for required fields
257+
nmos::experimental::make_control_class_property_descriptor(U("description"), { 3, 1 }, description_property, U("NcString"), true, false, false, false, web::json::value::null()),
258+
nmos::experimental::make_control_class_property_descriptor(U("resource_id"), { 3, 2 }, uuid_property, U("NcUuid"), true, false, false, false, web::json::value::null()),
259+
nmos::experimental::make_control_class_property_descriptor(U("label"), { 3, 3 }, label_property, U("NcString"), true, false, false, false, web::json::value::null()),
260+
nmos::experimental::make_control_class_property_descriptor(U("tags"), { 3, 4 }, tags_property, U("KeyValueStruct"), true, false, true, false, web::json::value::null()),
261+
nmos::experimental::make_control_class_property_descriptor(U("version"), { 3, 5 }, version_property, U("NcVersionCode"), true, false, false, false, web::json::value::null()),
262+
263+
// Property descriptor for optional fields
264+
nmos::experimental::make_control_class_property_descriptor(U("caps"), { 3, 6 }, caps_property, U("KeyValueStruct"), true, true, true, false, web::json::value::null()),
265+
nmos::experimental::make_control_class_property_descriptor(U("description"), { 3, 7 }, device_id_property, U("NcUuid"), true, true, false, false, web::json::value::null()),
266+
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()),
267+
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()),
268+
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()),
269+
nmos::experimental::make_control_class_property_descriptor(U("subscription"), { 3, 11 }, subscription_property, U("SubscriptionType"), true, true, false, false, web::json::value::null()),
270+
nmos::experimental::make_control_class_property_descriptor(U("transport"), { 3, 12 }, transport_property, U("NcString"), true, true, false, false, web::json::value::null())
271+
};
272+
// method and event descriptors are defined by defaults in the function prototype, so only need to pass the property descriptors
273+
utility::string_t descriptor_description = utility::string_t(U("SenderControl")) + utility::string_t(U("Sender control class descriptor"));
274+
auto sender_control_class_descriptor =
275+
nmos::experimental::make_control_class_descriptor(descriptor_description,
276+
snd_class_id, U("SenderControl"),
277+
snd_control_property_descriptors);
278+
279+
// Insert class descriptor into the nmos-cpp framework
280+
control_protocol_state.insert(std::move(sender_control_class_descriptor));
281+
}
282+
// Example of an sender control class
283+
static nmos::control_protocol_resource make_sender_control(const nmos::nc_class_id& snd_class_id,
284+
const web::json::value& sender_data,
285+
const nmos::nc_oid& oid,
286+
const utility::string_t& role,
287+
const nmos::nc_oid& parent_oid,
288+
const web::json::value& touchpoints)
289+
{
290+
using web::json::value;
291+
using web::json::value_of;
292+
auto make_key_value_array = [](const value& object)
293+
{
294+
auto key_value_array = value::array();
295+
296+
for (auto iter = object.as_object().begin(); iter != object.as_object().end(); iter++)
297+
{
298+
web::json::push_back(key_value_array, web::json::value_of({ { U("key"), (*iter).first}, {U("value"), (*iter).second } }));
299+
}
300+
return key_value_array;
301+
};
302+
303+
const web::json::field_as_array caps_property{ U("caps") };
304+
const web::json::field_as_string description_property{ U("description") };
305+
const web::json::field_as_string device_id_property{ U("device_id") };
306+
const web::json::field_as_string flow_id_property{ U("flow_id") };
307+
const web::json::field_as_string uuid_property{ U("resource_id") };
308+
const web::json::field_as_array interface_bindings_property{ U("interface_bindings") };
309+
const web::json::field_as_string label_property{ U("label") };
310+
const web::json::field_as_string manifest_href_property{ U("manifest_href") };
311+
const web::json::field_as_array subscription_property{ U("subscription") };
312+
const web::json::field_as_value tags_property{ U("tags") };
313+
const web::json::field_as_string transport_property{ U("transport") };
314+
const web::json::field<nmos::tai> version_property{ U("version") };
315+
316+
// define a function for instantiating object instances of the class
317+
auto data = nmos::nc::details::make_worker(snd_class_id, oid,
318+
true,
319+
parent_oid,
320+
role,
321+
web::json::value(role),
322+
U("Sender resource data"),
323+
touchpoints,
324+
web::json::value::null(),
325+
true);
326+
327+
// Required
328+
data[description_property] = sender_data.at(U("description"));
329+
data[uuid_property] = sender_data.at(U("id"));
330+
data[label_property] = sender_data.at(U("label"));
331+
data[tags_property] = make_key_value_array(sender_data.at(U("tags")));
332+
data[version_property] = sender_data.at(U("version"));
333+
// Optional
334+
data[caps_property] = sender_data.has_field(U("caps")) ? make_key_value_array(sender_data.at(U("caps"))) : web::json::value::array();
335+
data[device_id_property] = sender_data.has_field(U("device_id")) ? sender_data.at(U("device_id")) : web::json::value::null();
336+
data[flow_id_property] = sender_data.has_field(U("flow_id")) ? sender_data.at(U("flow_id")) : web::json::value::null();
337+
data[interface_bindings_property] = sender_data.has_field(U("interface_bindings")) ? sender_data.at(U("interface_bindings")) : web::json::value::array();
338+
data[manifest_href_property] = sender_data.has_field(U("manifest_href")) ? sender_data.at(U("manifest_href")) : web::json::value::null();
339+
data[subscription_property] = sender_data.has_field(U("subscription")) ? sender_data.at(U("subscription")) : web::json::value::null();
340+
data[transport_property] = sender_data.has_field(U("transport")) ? sender_data.at(U("transport")) : web::json::value::null();
341+
return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true };
342+
}
206343
}
207344

208345
// forward declarations for node_implementation_thread
@@ -1212,6 +1349,10 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr
12121349
return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true };
12131350
};
12141351

1352+
// example audio sender control descriptors
1353+
auto sender_control_class_id = nmos::nc::make_class_id(nmos::nc_worker_class_id, 0, { 5 });
1354+
impl::make_sender_control_descriptors(control_protocol_state, sender_control_class_id);
1355+
12151356
// example root block
12161357
auto root_block = nmos::make_root_block();
12171358

@@ -1275,12 +1416,12 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr
12751416
// making an object rebuildable allows read only properties to be modified by the Configuration API in Rebuild mode
12761417
nmos::make_rebuildable(example_control);
12771418

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

12851426
// example receiver-monitor(s)
12861427
{
@@ -1294,15 +1435,22 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr
12941435
utility::ostringstream_t role;
12951436
role << U("receiver-monitor-") << ++count;
12961437
const auto receiver = nmos::find_resource(model.node_resources, receiver_id);
1297-
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}) } }));
1438+
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}) } }));
12981439
// optionally indicate dependencies within the device model
1299-
nmos::set_object_dependency_paths(receiver_monitor, {{U("root"), U("receivers")}});
1440+
nmos::set_object_dependency_paths(receiver_monitor, {{U("root"), U("receiver-monitors")}});
13001441
// add receiver-monitor to receivers-block
1301-
nmos::nc::push_back(receivers_block, receiver_monitor);
1442+
nmos::nc::push_back(receiver_monitors_block, receiver_monitor);
13021443
}
13031444
}
13041445
}
13051446

1447+
const auto sender_monitors_block_oid = ++oid;
1448+
auto sender_monitors_block = nmos::make_block(sender_monitors_block_oid, nmos::root_block_oid, U("sender-monitors"), U("Sender Monitors"), U("Sender Monitors"));
1449+
// making a block rebuildable allows block members to be added or removed by the Configuration API in Rebuild mode
1450+
nmos::make_rebuildable(sender_monitors_block);
1451+
// restrict the allowed classes for members of this block
1452+
nmos::set_block_allowed_member_classes(sender_monitors_block, { nmos::nc_sender_monitor_class_id });
1453+
13061454
// example sender-monitor(s)
13071455
{
13081456
int count = 0;
@@ -1314,20 +1462,53 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr
13141462

13151463
utility::ostringstream_t role;
13161464
role << U("sender-monitor-") << ++count;
1317-
const auto sender = nmos::find_resource(model.node_resources, sender_id);
1318-
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}) } }));
1465+
const auto& sender = nmos::find_resource(model.node_resources, sender_id);
1466+
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}) } }));
1467+
// optionally indicate dependencies within the device model
1468+
nmos::set_object_dependency_paths(sender_monitor, { {U("root"), U("sender-monitors")} });
1469+
// add sender-monitor to sender-monitors-block
1470+
nmos::nc::push_back(sender_monitors_block, sender_monitor);
1471+
}
1472+
}
1473+
}
1474+
1475+
const auto sender_controls_block_oid = ++oid;
1476+
auto sender_controls_block = nmos::make_block(sender_controls_block_oid, nmos::root_block_oid, U("sender-controls"), U("Sender Controls"), U("Sender Controls"));
13191477

1320-
// add sender-monitor to root-block
1321-
nmos::nc::push_back(root_block, sender_monitor);
1478+
// example sender control(s)
1479+
{
1480+
int count = 0;
1481+
for (int index = 0; index < how_many; ++index)
1482+
{
1483+
for (const auto& port : rtp_receiver_ports)
1484+
{
1485+
1486+
const auto sender_id = impl::make_id(seed_id, nmos::types::sender, port, index);
1487+
1488+
utility::ostringstream_t role;
1489+
role << U("sender-control-") << ++count;
1490+
const auto sender = nmos::find_resource(model.node_resources, sender_id);
1491+
auto sender_control = impl::make_sender_control(sender_control_class_id,
1492+
sender->data,
1493+
++oid, role.str(),
1494+
sender_controls_block_oid,
1495+
value_of({ { nmos::nc::details::make_touchpoint_nmos({nmos::ncp_touchpoint_resource_types::sender, sender_id}) } }));
1496+
// add sender-control to sender-controls-block
1497+
nmos::nc::push_back(sender_controls_block, sender_control);
13221498
}
13231499
}
13241500
}
13251501

1502+
13261503
// example temperature-sensor
13271504
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"));
13281505

1329-
// add receivers-block to root-block
1330-
nmos::nc::push_back(root_block, receivers_block);
1506+
// add receiver-monitors-block to root-block
1507+
nmos::nc::push_back(root_block, receiver_monitors_block);
1508+
// add sender-monitors-block to root-block
1509+
nmos::nc::push_back(root_block, sender_monitors_block);
1510+
// add sender-controls-block to root-block
1511+
nmos::nc::push_back(root_block, sender_controls_block);
13311512
// add temperature-sensor to root-block
13321513
nmos::nc::push_back(root_block, temperature_sensor);
13331514
// add example-control to root-block

0 commit comments

Comments
 (0)