Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
bc41df2
Add RTP parameter sets and RTCP SDP support (alternative to #501) (#514)
garethsb Jul 29, 2026
1cc4221
Implement RFC 6364 SDP grammar
thangldw Jul 29, 2026
00db78d
Support IS-05 SMPTE 2022-5 FEC SDP
thangldw Jul 29, 2026
f95bbfe
Fix insert_resource corrupting sub_resources on rejected insert (#516)
garethsb Aug 3, 2026
3c91369
Fix path traversal vulnerability (#517)
lo-simon Aug 4, 2026
d047c9e
Allow extensibility of BCP-008 status monitors (#511)
jonathan-r-thorpe Aug 5, 2026
dac770c
Parse SDP encoding names and fmtp names case-insensitively (#518)
garethsb Aug 12, 2026
a19e364
Fix/negative logging categories (#519)
garethsb Aug 12, 2026
df7fc57
Fall back for invalid Node interface port IDs (#520)
shin4141 Aug 21, 2026
8360756
Align IS-05 v1.2 schemas with the published v1.2.x branch (#521)
garethsb Sep 3, 2026
8834906
Add IS-13 NMOS Annotation API support
garethsb Sep 17, 2026
8ba4886
Advertise authorization on the Annotation API service
garethsb Sep 27, 2026
fe30384
Merge pull request #331 from garethsb/rwnode
lo-simon Sep 29, 2026
47d9c3c
Cover RFC 6364 repair-flow syntax and IS-05 FEC mapping edges
lo-simon Sep 30, 2026
192c2fc
Merge pull request #515 from garethsb/fix/is05-fec-alt
lo-simon Oct 2, 2026
ce9e028
Refactor control protocol status monitoring by consolidating internal…
jonathan-r-thorpe Oct 5, 2026
b6c8367
Merge pull request #527 from jonathan-r-thorpe/bcp-008-cleanup
lo-simon Oct 5, 2026
566a54b
Merge Sony's master of 2026-10-05 (b6c8367) into bisect
pedro-alves-ferreira Oct 31, 2026
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
79 changes: 78 additions & 1 deletion Development/cmake/NmosCppLibraries.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ set(NMOS_IS05_SCHEMAS_HEADERS
nmos/is05_schemas/is05_schemas.h
)

set(NMOS_IS05_V1_2_TAG v1.2-dev)
set(NMOS_IS05_V1_2_TAG v1.2.x)
set(NMOS_IS05_V1_1_TAG v1.1.x)
set(NMOS_IS05_V1_0_TAG v1.0.x)

Expand All @@ -428,6 +428,7 @@ set(NMOS_IS05_V1_2_SCHEMAS_JSON
third_party/is-05/${NMOS_IS05_V1_2_TAG}/APIs/schemas/constraints-schema-rtp.json
third_party/is-05/${NMOS_IS05_V1_2_TAG}/APIs/schemas/constraints-schema-websocket.json
third_party/is-05/${NMOS_IS05_V1_2_TAG}/APIs/schemas/error.json
third_party/is-05/${NMOS_IS05_V1_2_TAG}/APIs/schemas/mxl_uuid.json
third_party/is-05/${NMOS_IS05_V1_2_TAG}/APIs/schemas/receiver_transport_params.json
third_party/is-05/${NMOS_IS05_V1_2_TAG}/APIs/schemas/receiver_transport_params_dash.json
third_party/is-05/${NMOS_IS05_V1_2_TAG}/APIs/schemas/receiver_transport_params_ext.json
Expand Down Expand Up @@ -882,6 +883,77 @@ target_include_directories(nmos_is12_schemas PUBLIC
list(APPEND NMOS_CPP_TARGETS nmos_is12_schemas)
add_library(nmos-cpp::nmos_is12_schemas ALIAS nmos_is12_schemas)

# nmos_is13_schemas library

set(NMOS_IS13_SCHEMAS_HEADERS
nmos/is13_schemas/is13_schemas.h
)

set(NMOS_IS13_V1_0_TAG v1.0-dev)

set(NMOS_IS13_V1_0_SCHEMAS_JSON
third_party/is-13/${NMOS_IS13_V1_0_TAG}/APIs/schemas/annotationapi-base.json
third_party/is-13/${NMOS_IS13_V1_0_TAG}/APIs/schemas/annotationapi-node-base.json
third_party/is-13/${NMOS_IS13_V1_0_TAG}/APIs/schemas/error.json
third_party/is-13/${NMOS_IS13_V1_0_TAG}/APIs/schemas/resource_core.json
third_party/is-13/${NMOS_IS13_V1_0_TAG}/APIs/schemas/resource_core_patch.json
third_party/is-13/${NMOS_IS13_V1_0_TAG}/APIs/schemas/resource-list.json
)

set(NMOS_IS13_SCHEMAS_JSON_MATCH "third_party/is-13/([^/]+)/APIs/schemas/([^;]+)\\.json")
set(NMOS_IS13_SCHEMAS_SOURCE_REPLACE "${CMAKE_CURRENT_BINARY_DIR_REPLACE}/nmos/is13_schemas/\\1/\\2.cpp")
string(REGEX REPLACE "${NMOS_IS13_SCHEMAS_JSON_MATCH}(;|$)" "${NMOS_IS13_SCHEMAS_SOURCE_REPLACE}\\3" NMOS_IS13_V1_0_SCHEMAS_SOURCES "${NMOS_IS13_V1_0_SCHEMAS_JSON}")

foreach(JSON ${NMOS_IS13_V1_0_SCHEMAS_JSON})
string(REGEX REPLACE "${NMOS_IS13_SCHEMAS_JSON_MATCH}" "${NMOS_IS13_SCHEMAS_SOURCE_REPLACE}" SOURCE "${JSON}")
string(REGEX REPLACE "${NMOS_IS13_SCHEMAS_JSON_MATCH}" "\\1" NS "${JSON}")
string(REGEX REPLACE "${NMOS_IS13_SCHEMAS_JSON_MATCH}" "\\2" VAR "${JSON}")
string(MAKE_C_IDENTIFIER "${NS}" NS)
string(MAKE_C_IDENTIFIER "${VAR}" VAR)

file(WRITE "${SOURCE}.in" "\
// Auto-generated from: ${JSON}\n\
\n\
namespace nmos\n\
{\n\
namespace is13_schemas\n\
{\n\
namespace ${NS}\n\
{\n\
const char* ${VAR} = R\"-auto-generated-(")

file(READ "${JSON}" RAW)
file(APPEND "${SOURCE}.in" "${RAW}")

file(APPEND "${SOURCE}.in" ")-auto-generated-\";\n\
}\n\
}\n\
}\n")

configure_file("${SOURCE}.in" "${SOURCE}" COPYONLY)
endforeach()

add_library(
nmos_is13_schemas STATIC
${NMOS_IS13_SCHEMAS_HEADERS}
${NMOS_IS13_V1_0_SCHEMAS_SOURCES}
)

source_group("nmos\\is13_schemas\\Header Files" FILES ${NMOS_IS13_SCHEMAS_HEADERS})
source_group("nmos\\is13_schemas\\${NMOS_IS13_V1_0_TAG}\\Source Files" FILES ${NMOS_IS13_V1_0_SCHEMAS_SOURCES})

target_link_libraries(
nmos_is13_schemas PRIVATE
nmos-cpp::compile-settings
)
target_include_directories(nmos_is13_schemas PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${NMOS_CPP_INSTALL_INCLUDEDIR}>
)

list(APPEND NMOS_CPP_TARGETS nmos_is13_schemas)
add_library(nmos-cpp::nmos_is13_schemas ALIAS nmos_is13_schemas)

# nmos_is14_schemas library

set(NMOS_IS14_SCHEMAS_HEADERS
Expand Down Expand Up @@ -1042,6 +1114,7 @@ set(NMOS_CPP_JWK_HEADERS
set(NMOS_CPP_NMOS_SOURCES
nmos/activation_utils.cpp
nmos/admin_ui.cpp
nmos/annotation_api.cpp
nmos/api_downgrade.cpp
nmos/api_utils.cpp
nmos/authorization.cpp
Expand Down Expand Up @@ -1096,6 +1169,7 @@ set(NMOS_CPP_NMOS_SOURCES
nmos/manifest_api.cpp
nmos/mdns.cpp
nmos/mdns_api.cpp
nmos/media_type.cpp
nmos/node_api.cpp
nmos/node_api_target_handler.cpp
nmos/node_behaviour.cpp
Expand Down Expand Up @@ -1135,6 +1209,7 @@ set(NMOS_CPP_NMOS_HEADERS
nmos/activation_mode.h
nmos/activation_utils.h
nmos/admin_ui.h
nmos/annotation_api.h
nmos/api_downgrade.h
nmos/api_utils.h
nmos/api_version.h
Expand Down Expand Up @@ -1200,6 +1275,7 @@ set(NMOS_CPP_NMOS_HEADERS
nmos/is09_versions.h
nmos/is10_versions.h
nmos/is12_versions.h
nmos/is13_versions.h
nmos/is14_versions.h
nmos/issuers.h
nmos/json_fields.h
Expand Down Expand Up @@ -1355,6 +1431,7 @@ target_link_libraries(
nmos-cpp::nmos_is09_schemas
nmos-cpp::nmos_is10_schemas
nmos-cpp::nmos_is12_schemas
nmos-cpp::nmos_is13_schemas
nmos-cpp::nmos_is14_schemas
nmos-cpp::mdns
nmos-cpp::slog
Expand Down
4 changes: 4 additions & 0 deletions Development/cmake/NmosCppTest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ set(NMOS_CPP_TEST_MDNS_TEST_HEADERS
)

set(NMOS_CPP_TEST_NMOS_TEST_SOURCES
nmos/test/annotation_api_test.cpp
nmos/test/api_utils_test.cpp
nmos/test/bcp_008_test.cpp
nmos/test/capabilities_test.cpp
nmos/test/channels_test.cpp
nmos/test/condition_variable_test.cpp
nmos/test/connection_resources_test.cpp
nmos/test/configuration_methods_test.cpp
nmos/test/configuration_resources_test.cpp
nmos/test/configuration_utils_test.cpp
Expand All @@ -56,10 +58,12 @@ set(NMOS_CPP_TEST_NMOS_TEST_SOURCES
nmos/test/json_validator_test.cpp
nmos/test/jwt_generator_test.cpp
nmos/test/jwt_validation_test.cpp
nmos/test/log_gate_test.cpp
nmos/test/mdns_test.cpp
nmos/test/node_interfaces_test.cpp
nmos/test/paging_utils_test.cpp
nmos/test/query_api_test.cpp
nmos/test/resources_test.cpp
nmos/test/sdp_test_utils.cpp
nmos/test/sdp_temporal_redundancy_test.cpp
nmos/test/sdp_utils_test.cpp
Expand Down
6 changes: 6 additions & 0 deletions Development/nmos-cpp-node/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@
//"logging_level": 0,

// logging_categories [registry, node]: array of logging categories to be included in the error log
// categories prefixed with '!' are excluded, even if another category matches positively;
// "!" excludes messages with no category; when only excluded categories are specified, all other log messages are included
//"logging_categories": ["node_implementation"],

// Configuration settings and defaults for the NMOS APIs
Expand Down Expand Up @@ -129,6 +131,9 @@
// is12_versions [node]: used to specify the enabled API versions for a version-locked configuration
//"is12_versions": ["v1.0"],

// is13_versions [node]: used to specify the enabled API versions for a version-locked configuration
//"is13_versions": ["v1.0"],

// pri [registry, node]: used for the 'pri' TXT record; specifying nmos::service_priorities::no_priority (maximum value) disables advertisement completely
//"pri": 100,

Expand Down Expand Up @@ -171,6 +176,7 @@
//"system_port": 10641,
// control_protocol_ws_port [node]: used to construct request URLs for the Control Protocol websocket, or negative to disable the control protocol features
//"control_protocol_ws_port": 3218,
//"annotation_port": 3212,
//"configuration_port": 3219,

// listen_backlog [registry, node]: the maximum length of the queue of pending connections, or zero for the implementation default (the implementation may not honour this value)
Expand Down
45 changes: 44 additions & 1 deletion Development/nmos-cpp-node/node_implementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1779,6 +1779,8 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr
nmos::set_block_allowed_member_classes(receiver_monitors_block, {nmos::nc_receiver_monitor_class_id});

// example receiver-monitor(s)
// For an example of defining a custom status monitor (derived class + monitor domains), see
// testSetDerivedMonitorDomainStatus in nmos/test/control_protocol_utils_test.cpp
{
int count = 0;
for (int index = 0; index < how_many; ++index)
Expand Down Expand Up @@ -2248,7 +2250,7 @@ nmos::transport_file_parser make_node_implementation_transport_file_parser()
// ── RTP path ────────────────────────────────────────────────────
const auto validate_sdp_parameters = [](const web::json::value& receiver, const nmos::sdp_parameters& sdp_params)
{
if (nmos::media_types::video_jxsv == nmos::get_media_type(sdp_params))
if (equals_media_type(nmos::media_types::video_jxsv, nmos::get_media_type(sdp_params)))
{
nmos::validate_video_jxsv_sdp_parameters(receiver, sdp_params);
}
Expand Down Expand Up @@ -2327,6 +2329,25 @@ nmos::connection_resource_auto_resolver make_node_implementation_auto_resolver(c
const bool smpte2022_7 = 1 < transport_params.size();
nmos::details::resolve_auto(transport_params[0], nmos::fields::interface_ip, [&] { return web::json::front(nmos::fields::constraint_enum(constraints.at(0).at(nmos::fields::interface_ip))); });
if (smpte2022_7) nmos::details::resolve_auto(transport_params[1], nmos::fields::interface_ip, [&] { return web::json::back(nmos::fields::constraint_enum(constraints.at(1).at(nmos::fields::interface_ip))); });
for (size_t leg = 0; leg < transport_params.size(); ++leg)
{
auto& params = transport_params.at(leg);
// The IS-05 receiver schema defines "auto" as the highest available number of dimensions.
nmos::details::resolve_auto(params, nmos::fields::fec_mode, [&] {
const auto& constraint = constraints.at(leg).at(nmos::fields::fec_mode);
if (constraint.has_field(nmos::fields::constraint_enum))
{
const auto& modes = nmos::fields::constraint_enum(constraint).as_array();
const auto has_2d = modes.end() != boost::range::find_if(modes, [](const value& mode)
{
return mode.is_string() && U("2D") == mode.as_string();
});
return value::string(has_2d ? U("2D") : U("1D"));
}
// unconstrained: highest available in the schema
return value::string(U("2D"));
});
}
// lastly, apply the specification defaults for any properties not handled above
nmos::resolve_rtp_auto(id_type.second, transport_params);
}
Expand Down Expand Up @@ -2630,6 +2651,27 @@ nmos::channelmapping_activation_handler make_node_implementation_channelmapping_
};
}

// Example Annotation API patch callback to update resource labels, descriptions and tags
nmos::annotation_patch_merger make_node_implementation_annotation_patch_merger(const nmos::settings& settings, slog::base_gate& gate)
{
using web::json::value;
using web::json::value_of;

return [&settings, &gate](const nmos::resource& resource, web::json::value& value, const web::json::value& patch)
{
const std::pair<nmos::id, nmos::type> id_type{ resource.id, resource.type };
slog::log<slog::severities::info>(gate, SLOG_FLF) << nmos::stash_category(impl::categories::node_implementation) << "Updating " << id_type;
// this example uses the specified tags for node and device resources as defaults
const auto default_tags
= id_type.second == nmos::types::node ? impl::fields::node_tags(settings)
: id_type.second == nmos::types::device ? impl::fields::device_tags(settings)
: value::object();
// and uses the default predicate for read-only tags
nmos::details::merge_annotation_patch(value, patch, &nmos::details::is_read_only_tag, value_of({ { nmos::fields::tags, default_tags } }));
// this example does not save the new values to persistent storage or e.g. reject values that are too large
};
}

// Example Control Protocol WebSocket API property changed callback to perform application-specific operations to complete the property changed
nmos::control_protocol_property_changed_handler make_node_implementation_control_protocol_property_changed_handler(slog::base_gate& gate)
{
Expand Down Expand Up @@ -3025,6 +3067,7 @@ nmos::experimental::node_implementation make_node_implementation(nmos::node_mode
.on_connection_activated(make_node_implementation_connection_activation_handler(model, gate))
.on_validate_channelmapping_output_map(make_node_implementation_map_validator()) // may be omitted if not required
.on_channelmapping_activated(make_node_implementation_channelmapping_activation_handler(gate))
.on_merge_annotation_patch(make_node_implementation_annotation_patch_merger(model.settings, gate)) // may be omitted if not required
.on_control_protocol_property_changed(make_node_implementation_control_protocol_property_changed_handler(gate)) // may be omitted if IS-12 not required
.on_create_validation_fingerprint(make_create_validation_fingerprint_handler())
.on_validate_validation_fingerprint(make_validate_validation_fingerprint_handler())
Expand Down
2 changes: 2 additions & 0 deletions Development/nmos-cpp-registry/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
//"logging_level": 0,

// logging_categories [registry, node]: array of logging categories to be included in the error log
// categories prefixed with '!' are excluded, even if another category matches positively;
// "!" excludes messages with no category; when only excluded categories are specified, all other log messages are included
//"logging_categories": ["send_query_ws_events"],

// Configuration settings and defaults for the NMOS APIs
Expand Down
Loading