@@ -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