diff --git a/Development/bst/test/detail/boost_1_57_0.h b/Development/bst/test/detail/boost_1_57_0.h index dabf7f04c..4c47aac38 100644 --- a/Development/bst/test/detail/boost_1_57_0.h +++ b/Development/bst/test/detail/boost_1_57_0.h @@ -51,6 +51,7 @@ PRAGMA_WARNING_POP #define BST_CHECK_GT(expected, actual) BOOST_CHECK_GT(expected, actual) #define BST_CHECK_GE(expected, actual) BOOST_CHECK_GE(expected, actual) #define BST_CHECK_THROW(expr, exception) BOOST_CHECK_THROW(expr, exception) +#define BST_CHECK_NO_THROW(expr) BOOST_CHECK_NO_THROW(expr) #define BST_REQUIRE(expr) BOOST_REQUIRE(expr) #define BST_REQUIRE_EQUAL(expected, actual) BOOST_REQUIRE_EQUAL(expected, actual) #define BST_REQUIRE_NE(expected, actual) BOOST_REQUIRE_NE(expected, actual) @@ -59,6 +60,7 @@ PRAGMA_WARNING_POP #define BST_REQUIRE_GT(expected, actual) BOOST_REQUIRE_GT(expected, actual) #define BST_REQUIRE_GE(expected, actual) BOOST_REQUIRE_GE(expected, actual) #define BST_REQUIRE_THROW(expr, exception) BOOST_REQUIRE_THROW(expr, exception) +#define BST_REQUIRE_NO_THROW(expr) BOOST_REQUIRE_NO_THROW(expr) #define BST_WARN(expr) BOOST_WARN(expr) #define BST_WARN_EQUAL(expected, actual) BOOST_WARN_EQUAL(expected, actual) #define BST_WARN_NE(expected, actual) BOOST_WARN_NE(expected, actual) @@ -66,6 +68,8 @@ PRAGMA_WARNING_POP #define BST_WARN_LE(expected, actual) BOOST_WARN_LE(expected, actual) #define BST_WARN_GT(expected, actual) BOOST_WARN_GT(expected, actual) #define BST_WARN_GE(expected, actual) BOOST_WARN_GE(expected, actual) +#define BST_WARN_THROW(expr, exception) BOOST_WARN_THROW(expr, exception) +#define BST_WARN_NO_THROW(expr) BOOST_WARN_NO_THROW(expr) // Explicit STRING macros to work around the different behaviours of the frameworks when comparing two char* or wchar_t* #define BST_CHECK_STRING_EQUAL(expected, actual) BOOST_CHECK_EQUAL(expected, actual) diff --git a/Development/bst/test/detail/boost_1_65_1.h b/Development/bst/test/detail/boost_1_65_1.h index 16ed593fc..4ed0ad9e0 100644 --- a/Development/bst/test/detail/boost_1_65_1.h +++ b/Development/bst/test/detail/boost_1_65_1.h @@ -56,6 +56,7 @@ do { #define BST_CHECK_GT(expected, actual) BOOST_CHECK_GT(expected, actual) #define BST_CHECK_GE(expected, actual) BOOST_CHECK_GE(expected, actual) #define BST_CHECK_THROW(expr, exception) BOOST_CHECK_THROW(expr, exception) +#define BST_CHECK_NO_THROW(expr) BOOST_CHECK_NO_THROW(expr) #define BST_REQUIRE(expr) BOOST_REQUIRE(expr) #define BST_REQUIRE_EQUAL(expected, actual) BOOST_REQUIRE_EQUAL(expected, actual) #define BST_REQUIRE_NE(expected, actual) BOOST_REQUIRE_NE(expected, actual) @@ -64,6 +65,7 @@ do { #define BST_REQUIRE_GT(expected, actual) BOOST_REQUIRE_GT(expected, actual) #define BST_REQUIRE_GE(expected, actual) BOOST_REQUIRE_GE(expected, actual) #define BST_REQUIRE_THROW(expr, exception) BOOST_REQUIRE_THROW(expr, exception) +#define BST_REQUIRE_NO_THROW(expr) BOOST_REQUIRE_NO_THROW(expr) #define BST_WARN(expr) BOOST_WARN(expr) #define BST_WARN_EQUAL(expected, actual) BOOST_WARN_EQUAL(expected, actual) #define BST_WARN_NE(expected, actual) BOOST_WARN_NE(expected, actual) @@ -71,6 +73,8 @@ do { #define BST_WARN_LE(expected, actual) BOOST_WARN_LE(expected, actual) #define BST_WARN_GT(expected, actual) BOOST_WARN_GT(expected, actual) #define BST_WARN_GE(expected, actual) BOOST_WARN_GE(expected, actual) +#define BST_WARN_THROW(expr, exception) BOOST_WARN_THROW(expr, exception) +#define BST_WARN_NO_THROW(expr) BOOST_WARN_NO_THROW(expr) // Explicit STRING macros to work around the different behaviours of the frameworks when comparing two char* or wchar_t* #define BST_CHECK_STRING_EQUAL(expected, actual) BOOST_CHECK_EQUAL(expected, actual) diff --git a/Development/bst/test/detail/catch-1.0.h b/Development/bst/test/detail/catch-1.0.h index 6ae159f4f..d9b984e8f 100644 --- a/Development/bst/test/detail/catch-1.0.h +++ b/Development/bst/test/detail/catch-1.0.h @@ -53,7 +53,9 @@ PRAGMA_WARNING_POP #define CATCH_CHECK_CATCH_AS( exceptionType ) INTERNAL_CATCH_CATCH_AS( exceptionType ) #define CATCH_CHECK_CATCH_AS_NOFAIL( exceptionType ) INTERNAL_CATCH_CATCH_AS( exceptionType ) +#define CATCH_CHECK_THROWS_NOFAIL( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_THROWS_NOFAIL" ) #define CATCH_CHECK_THROWS_AS_NOFAIL( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_THROWS_AS_NOFAIL" ) +#define CATCH_CHECK_NOTHROW_NOFAIL( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOTHROW_NOFAIL" ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -66,7 +68,9 @@ PRAGMA_WARNING_POP #define CHECK_CATCH_AS( exceptionType ) INTERNAL_CATCH_CATCH_AS( exceptionType ) #define CHECK_CATCH_AS_NOFAIL( exceptionType ) INTERNAL_CATCH_CATCH_AS( exceptionType ) +#define CHECK_THROWS_NOFAIL( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_THROWS_NOFAIL" ) #define CHECK_THROWS_AS_NOFAIL( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_THROWS_AS_NOFAIL" ) +#define CHECK_NOTHROW_NOFAIL( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOTHROW_NOFAIL" ) #endif //- Break INTERNAL_CATCH_THROWS_AS in two so the statement can contain commas, etc. @@ -222,6 +226,7 @@ PRAGMA_WARNING_POP #define BST_CHECK_GT(expected, actual) CATCH_CHECK((expected) > (actual)) #define BST_CHECK_GE(expected, actual) CATCH_CHECK((expected) >= (actual)) #define BST_CHECK_THROW(expr, exception) CATCH_CHECK_THROWS_AS(expr, exception) +#define BST_CHECK_NO_THROW(expr) CATCH_CHECK_NOTHROW(expr) #define BST_REQUIRE(expr) CATCH_REQUIRE(expr) #define BST_REQUIRE_EQUAL(expected, actual) CATCH_REQUIRE((expected) == (actual)) #define BST_REQUIRE_NE(expected, actual) CATCH_REQUIRE((expected) != (actual)) @@ -230,6 +235,7 @@ PRAGMA_WARNING_POP #define BST_REQUIRE_GT(expected, actual) CATCH_REQUIRE((expected) > (actual)) #define BST_REQUIRE_GE(expected, actual) CATCH_REQUIRE((expected) >= (actual)) #define BST_REQUIRE_THROW(expr, exception) CATCH_REQUIRE_THROWS_AS(expr, exception) +#define BST_REQUIRE_NO_THROW(expr) CATCH_REQUIRE_NOTHROW(expr) #define BST_WARN(expr) CATCH_CHECK_NOFAIL(expr) #define BST_WARN_EQUAL(expected, actual) CATCH_CHECK_NOFAIL((expected) == (actual)) #define BST_WARN_NE(expected, actual) CATCH_CHECK_NOFAIL((expected) != (actual)) @@ -237,6 +243,8 @@ PRAGMA_WARNING_POP #define BST_WARN_LE(expected, actual) CATCH_CHECK_NOFAIL((expected) <= (actual)) #define BST_WARN_GT(expected, actual) CATCH_CHECK_NOFAIL((expected) > (actual)) #define BST_WARN_GE(expected, actual) CATCH_CHECK_NOFAIL((expected) >= (actual)) +#define BST_WARN_THROW(expr, exception) CATCH_CHECK_THROWS_AS_NOFAIL(expr, exception) +#define BST_WARN_NO_THROW(expr) CATCH_CHECK_NOTHROW_NOFAIL(expr) // Explicit STRING macros to work around the different behaviours of the frameworks when comparing two char* or wchar_t* namespace bst_test_detail diff --git a/Development/bst/test/detail/catch-1.10.0.h b/Development/bst/test/detail/catch-1.10.0.h index 90c1370d9..25db7ddbe 100644 --- a/Development/bst/test/detail/catch-1.10.0.h +++ b/Development/bst/test/detail/catch-1.10.0.h @@ -53,7 +53,9 @@ PRAGMA_WARNING_POP #define CATCH_CHECK_CATCH_AS( exceptionType ) INTERNAL_CATCH_CATCH_AS( exceptionType ) #define CATCH_CHECK_CATCH_AS_NOFAIL( exceptionType ) INTERNAL_CATCH_CATCH_AS( exceptionType ) +#define CATCH_CHECK_THROWS_NOFAIL( expr ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "", expr ) #define CATCH_CHECK_THROWS_AS_NOFAIL( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS_NOFAIL", exceptionType, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) +#define CATCH_CHECK_NOTHROW_NOFAIL( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -66,7 +68,9 @@ PRAGMA_WARNING_POP #define CHECK_CATCH_AS( exceptionType ) INTERNAL_CATCH_CATCH_AS( exceptionType ) #define CHECK_CATCH_AS_NOFAIL( exceptionType ) INTERNAL_CATCH_CATCH_AS( exceptionType ) +#define CHECK_THROWS_NOFAIL( expr ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "", expr ) #define CHECK_THROWS_AS_NOFAIL( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS_NOFAIL", exceptionType, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) +#define CHECK_NOTHROW_NOFAIL( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) #endif //- Break INTERNAL_CATCH_THROWS_AS in two so the statement can contain commas, etc. @@ -231,6 +235,7 @@ PRAGMA_WARNING_POP #define BST_CHECK_GT(expected, actual) CATCH_CHECK((expected) > (actual)) #define BST_CHECK_GE(expected, actual) CATCH_CHECK((expected) >= (actual)) #define BST_CHECK_THROW(expr, exception) CATCH_CHECK_THROWS_AS(expr, exception) +#define BST_CHECK_NO_THROW(expr) CATCH_CHECK_NOTHROW(expr) #define BST_REQUIRE(expr) CATCH_REQUIRE(expr) #define BST_REQUIRE_EQUAL(expected, actual) CATCH_REQUIRE((expected) == (actual)) #define BST_REQUIRE_NE(expected, actual) CATCH_REQUIRE((expected) != (actual)) @@ -239,6 +244,7 @@ PRAGMA_WARNING_POP #define BST_REQUIRE_GT(expected, actual) CATCH_REQUIRE((expected) > (actual)) #define BST_REQUIRE_GE(expected, actual) CATCH_REQUIRE((expected) >= (actual)) #define BST_REQUIRE_THROW(expr, exception) CATCH_REQUIRE_THROWS_AS(expr, exception) +#define BST_REQUIRE_NO_THROW(expr) CATCH_REQUIRE_NOTHROW(expr) #define BST_WARN(expr) CATCH_CHECK_NOFAIL(expr) #define BST_WARN_EQUAL(expected, actual) CATCH_CHECK_NOFAIL((expected) == (actual)) #define BST_WARN_NE(expected, actual) CATCH_CHECK_NOFAIL((expected) != (actual)) @@ -246,6 +252,8 @@ PRAGMA_WARNING_POP #define BST_WARN_LE(expected, actual) CATCH_CHECK_NOFAIL((expected) <= (actual)) #define BST_WARN_GT(expected, actual) CATCH_CHECK_NOFAIL((expected) > (actual)) #define BST_WARN_GE(expected, actual) CATCH_CHECK_NOFAIL((expected) >= (actual)) +#define BST_WARN_THROW(expr, exception) CATCH_CHECK_THROWS_AS_NOFAIL(expr, exception) +#define BST_WARN_NO_THROW(expr) CATCH_CHECK_NOTHROW_NOFAIL(expr) // Explicit STRING macros to work around the different behaviours of the frameworks when comparing two char* or wchar_t* namespace bst_test_detail diff --git a/Development/bst/test/detail/googletest-release-1.7.0.h b/Development/bst/test/detail/googletest-release-1.7.0.h index 7f7f58440..fbea91907 100644 --- a/Development/bst/test/detail/googletest-release-1.7.0.h +++ b/Development/bst/test/detail/googletest-release-1.7.0.h @@ -86,6 +86,7 @@ #define BST_CHECK_GT(expected, actual) EXPECT_GT(expected, actual) #define BST_CHECK_GE(expected, actual) EXPECT_GE(expected, actual) #define BST_CHECK_THROW(expr, exception) EXPECT_THROW(expr, exception) +#define BST_CHECK_NO_THROW(expr) EXPECT_NO_THROW(expr) #define BST_REQUIRE(expr) ASSERT_TRUE(expr) #define BST_REQUIRE_EQUAL(expected, actual) ASSERT_EQ(expected, actual) #define BST_REQUIRE_NE(expected, actual) ASSERT_NE(expected, actual) @@ -94,6 +95,7 @@ #define BST_REQUIRE_GT(expected, actual) ASSERT_GT(expected, actual) #define BST_REQUIRE_GE(expected, actual) ASSERT_GE(expected, actual) #define BST_REQUIRE_THROW(expr, exception) ASSERT_THROW(expr, exception) +#define BST_REQUIRE_NO_THROW(expr) ASSERT_NO_THROW(expr) // Hmm, Google Test doesn't have the equivalent of WARN? #define BST_WARN(expr) EXPECT_TRUE(expr) #define BST_WARN_EQUAL(expected, actual) EXPECT_EQ(expected, actual) @@ -102,6 +104,8 @@ #define BST_WARN_LE(expected, actual) EXPECT_LE(expected, actual) #define BST_WARN_GT(expected, actual) EXPECT_GT(expected, actual) #define BST_WARN_GE(expected, actual) EXPECT_GE(expected, actual) +#define BST_WARN_THROW(expr, exception) EXPECT_THROW(expr, exception) +#define BST_WARN_NO_THROW(expr) EXPECT_NO_THROW(expr) // Explicit STRING macros to work around the different behaviours of the frameworks when comparing two char* or wchar_t* namespace bst_test_detail diff --git a/Development/bst/test/detail/googletest-release-1.8.0.h b/Development/bst/test/detail/googletest-release-1.8.0.h index 97b327a79..86af8edd3 100644 --- a/Development/bst/test/detail/googletest-release-1.8.0.h +++ b/Development/bst/test/detail/googletest-release-1.8.0.h @@ -87,6 +87,7 @@ #define BST_CHECK_GT(expected, actual) EXPECT_GT(expected, actual) #define BST_CHECK_GE(expected, actual) EXPECT_GE(expected, actual) #define BST_CHECK_THROW(expr, exception) EXPECT_THROW(expr, exception) +#define BST_CHECK_NO_THROW(expr) EXPECT_NO_THROW(expr) #define BST_REQUIRE(expr) ASSERT_TRUE(expr) #define BST_REQUIRE_EQUAL(expected, actual) ASSERT_EQ(expected, actual) #define BST_REQUIRE_NE(expected, actual) ASSERT_NE(expected, actual) @@ -95,6 +96,7 @@ #define BST_REQUIRE_GT(expected, actual) ASSERT_GT(expected, actual) #define BST_REQUIRE_GE(expected, actual) ASSERT_GE(expected, actual) #define BST_REQUIRE_THROW(expr, exception) ASSERT_THROW(expr, exception) +#define BST_REQUIRE_NO_THROW(expr) ASSERT_NO_THROW(expr) // Hmm, Google Test doesn't have the equivalent of WARN? #define BST_WARN(expr) EXPECT_TRUE(expr) #define BST_WARN_EQUAL(expected, actual) EXPECT_EQ(expected, actual) @@ -103,6 +105,8 @@ #define BST_WARN_LE(expected, actual) EXPECT_LE(expected, actual) #define BST_WARN_GT(expected, actual) EXPECT_GT(expected, actual) #define BST_WARN_GE(expected, actual) EXPECT_GE(expected, actual) +#define BST_WARN_THROW(expr, exception) EXPECT_THROW(expr, exception) +#define BST_WARN_NO_THROW(expr) EXPECT_NO_THROW(expr) // Explicit STRING macros to work around the different behaviours of the frameworks when comparing two char* or wchar_t* namespace bst_test_detail diff --git a/Development/cmake/NmosCppLibraries.cmake b/Development/cmake/NmosCppLibraries.cmake index fc9933e6a..6028e53e0 100644 --- a/Development/cmake/NmosCppLibraries.cmake +++ b/Development/cmake/NmosCppLibraries.cmake @@ -885,6 +885,7 @@ set(NMOS_CPP_NMOS_HEADERS nmos/slog.h nmos/ssl_context_options.h nmos/string_enum.h + nmos/string_enum_fwd.h nmos/system_api.h nmos/system_resources.h nmos/tai.h diff --git a/Development/nmos/channelmapping_resources.cpp b/Development/nmos/channelmapping_resources.cpp index e2a6cee5a..7e738c98c 100644 --- a/Development/nmos/channelmapping_resources.cpp +++ b/Development/nmos/channelmapping_resources.cpp @@ -122,7 +122,7 @@ namespace nmos using web::json::value; using web::json::value_of; - const bool empty = id.empty() || type.name.empty(); + const bool empty = id.empty() || type.empty(); return value_of({ { nmos::fields::id, empty ? value::null() : value::string(id) }, { nmos::fields::type, empty ? value::null() : value::string(type.name) } diff --git a/Development/nmos/components.cpp b/Development/nmos/components.cpp index 7011bdda7..d3c2d3065 100644 --- a/Development/nmos/components.cpp +++ b/Development/nmos/components.cpp @@ -29,7 +29,7 @@ namespace nmos make_component(component_names::B, frame_width, frame_height, bit_depth) }); case YCbCr422: - return value_of({ + return value_of({ make_component(component_names::Y, frame_width, frame_height, bit_depth), make_component(component_names::Cb, frame_width / 2, frame_height, bit_depth), make_component(component_names::Cr, frame_width / 2, frame_height, bit_depth) diff --git a/Development/nmos/group_hint.cpp b/Development/nmos/group_hint.cpp index cbd264f58..79373ded1 100644 --- a/Development/nmos/group_hint.cpp +++ b/Development/nmos/group_hint.cpp @@ -6,7 +6,7 @@ namespace nmos { utility::string_t make_group_hint(const group_hint& group_hint) { - return group_hint.optional_group_scope.name.empty() + return group_hint.optional_group_scope.empty() ? group_hint.group_name + U(':') + group_hint.role_in_group : group_hint.group_name + U(':') + group_hint.role_in_group + U(':') + group_hint.optional_group_scope.name; } diff --git a/Development/nmos/node_resources.cpp b/Development/nmos/node_resources.cpp index 537042051..3d14adb79 100644 --- a/Development/nmos/node_resources.cpp +++ b/Development/nmos/node_resources.cpp @@ -139,7 +139,7 @@ namespace nmos data[U("caps")] = value::object(); data[U("device_id")] = value::string(device_id); data[U("parents")] = value::array(); - data[U("clock_name")] = !clk.name.empty() ? value::string(clk.name) : value::null(); + data[U("clock_name")] = !clk.empty() ? value::string(clk.name) : value::null(); return{ is04_versions::v1_3, types::source, std::move(data), false }; } @@ -406,7 +406,7 @@ namespace nmos data[U("format")] = value::string(nmos::formats::data.name); data[U("media_type")] = value::string(nmos::media_types::application_json.name); - if (!event_type.name.empty()) + if (!event_type.empty()) { data[U("event_type")] = value::string(event_type.name); } diff --git a/Development/nmos/query_api.cpp b/Development/nmos/query_api.cpp index 646bad83b..57e408832 100644 --- a/Development/nmos/query_api.cpp +++ b/Development/nmos/query_api.cpp @@ -274,7 +274,7 @@ namespace nmos href_type = fields.end() != field ? field->second : nmos::type{}; } - else if (href_type.name.empty()) + else if (href_type.empty()) { assign(std::move(value)); } diff --git a/Development/nmos/sdp_utils.cpp b/Development/nmos/sdp_utils.cpp index 42ec04573..10b2ee5a2 100644 --- a/Development/nmos/sdp_utils.cpp +++ b/Development/nmos/sdp_utils.cpp @@ -468,7 +468,7 @@ namespace nmos // Bandwidth // See https://tools.ietf.org/html/rfc4566#section-5.8 - { !sdp_params.bandwidth.bandwidth_type.name.empty() ? sdp::fields::bandwidth_information.key : U(""), value_of({ + { !sdp_params.bandwidth.bandwidth_type.empty() ? sdp::fields::bandwidth_information.key : U(""), value_of({ value_of({ { sdp::fields::bandwidth_type, sdp_params.bandwidth.bandwidth_type.name }, { sdp::fields::bandwidth, sdp_params.bandwidth.bandwidth } @@ -525,7 +525,7 @@ namespace nmos ); } - // insert source-filter if source address is specified, depending on source_filters + // insert source-filter if source address is specified, depending on source_filters // for now, when source_filters does not contain an explicit value, the default is to include the source-filter attribute // another choice would be to do so only for source-specific multicast addresses (232.0.0.0-232.255.255.255) const auto& source_ip = nmos::fields::source_ip(transport_param); @@ -703,10 +703,10 @@ namespace nmos fmtp.push_back({ sdp::fields::sampling, params.sampling.name }); fmtp.push_back({ sdp::fields::depth, utility::ostringstreamed(params.depth) }); fmtp.push_back({ sdp::fields::colorimetry, params.colorimetry.name }); - if (!params.tcs.name.empty()) fmtp.push_back({ sdp::fields::transfer_characteristic_system, params.tcs.name }); + if (!params.tcs.empty()) fmtp.push_back({ sdp::fields::transfer_characteristic_system, params.tcs.name }); fmtp.push_back({ sdp::fields::packing_mode, sdp::packing_modes::general.name }); // or block... fmtp.push_back({ sdp::fields::smpte_standard_number, sdp::smpte_standard_numbers::ST2110_20_2017.name }); - if (!params.tp.name.empty()) fmtp.push_back({ sdp::fields::type_parameter, params.tp.name }); + if (!params.tp.empty()) fmtp.push_back({ sdp::fields::type_parameter, params.tp.name }); return{ session_name, sdp::media_types::video, rtpmap, fmtp, {}, {}, {}, {}, media_stream_ids, ts_refclk }; } @@ -754,7 +754,7 @@ namespace nmos // a=fmtp: // See https://tools.ietf.org/html/rfc4566#section-6 sdp_parameters::fmtp_t fmtp = {}; - if (!params.tp.name.empty()) fmtp.push_back({ sdp::fields::type_parameter, params.tp.name }); + if (!params.tp.empty()) fmtp.push_back({ sdp::fields::type_parameter, params.tp.name }); return{ session_name, sdp::media_types::video, rtpmap, fmtp, {}, {}, {}, {}, media_stream_ids, ts_refclk }; } @@ -1287,6 +1287,7 @@ namespace nmos params.sample_rate = sdp_params.rtpmap.clock_rate; params.channel_count = (uint32_t)sdp_params.rtpmap.encoding_parameters; + if (0 == params.channel_count) params.channel_count = 1; // optional const auto channel_order = find_fmtp(sdp_params.fmtp, sdp::fields::channel_order); @@ -1405,7 +1406,7 @@ namespace nmos { // General Constraints - { nmos::caps::format::media_type, [](CAPS_ARGS) { return nmos::match_string_constraint(sdp.media_type.name, con); } }, + { nmos::caps::format::media_type, [](CAPS_ARGS) { return nmos::match_string_constraint(get_media_type(sdp).name, con); } }, // hm, how best to match (rational) nmos::caps::format::grain_rate against (double) framerate e.g. for video/SMPTE2022-6? // is 23.976 a match for 24000/1001? how about 23.98, or 23.9? or even 23?! { nmos::caps::format::grain_rate, [](CAPS_ARGS) { auto video = get_video(&format); return !video || nmos::rational{} == video->exactframerate || nmos::match_rational_constraint(video->exactframerate, con); } }, @@ -1417,7 +1418,7 @@ namespace nmos { nmos::caps::format::color_sampling, [](CAPS_ARGS) { auto video = get_video(&format); return video && nmos::match_string_constraint(video->sampling.name, con); } }, { nmos::caps::format::interlace_mode, [](CAPS_ARGS) { auto video = get_video(&format); return video && nmos::match_interlace_mode_constraint(video->interlace, video->segmented, con); } }, { nmos::caps::format::colorspace, [](CAPS_ARGS) { auto video = get_video(&format); return video && nmos::match_string_constraint(video->colorimetry.name, con); } }, - { nmos::caps::format::transfer_characteristic, [](CAPS_ARGS) { auto video = get_video(&format); return video && nmos::match_string_constraint(video->tcs.name, con); } }, + { nmos::caps::format::transfer_characteristic, [](CAPS_ARGS) { auto video = get_video(&format); return video && nmos::match_string_constraint(!video->tcs.empty() ? video->tcs.name : sdp::transfer_characteristic_systems::SDR.name, con); } }, { nmos::caps::format::component_depth, [](CAPS_ARGS) { auto video = get_video(&format); return video && nmos::match_integer_constraint(video->depth, con); } }, // Audio Constraints @@ -1428,8 +1429,8 @@ namespace nmos // Transport Constraints - { nmos::caps::transport::packet_time, [](CAPS_ARGS) { return nmos::match_number_constraint(sdp.packet_time, con); } }, - { nmos::caps::transport::max_packet_time, [](CAPS_ARGS) { return nmos::match_number_constraint(sdp.max_packet_time, con); } }, + { nmos::caps::transport::packet_time, [](CAPS_ARGS) { return 0 == sdp.packet_time || nmos::match_number_constraint(sdp.packet_time, con); } }, + { nmos::caps::transport::max_packet_time, [](CAPS_ARGS) { return 0 == sdp.max_packet_time || nmos::match_number_constraint(sdp.max_packet_time, con); } }, { nmos::caps::transport::st2110_21_sender_type, [](CAPS_ARGS) { if (auto video = get_video(&format)) return nmos::match_string_constraint(video->tp.name, con); else if (auto mux = get_mux(&format)) return nmos::match_string_constraint(mux->tp.name, con); else return false; } } }; #undef CAPS_ARGS diff --git a/Development/nmos/server_utils.cpp b/Development/nmos/server_utils.cpp index e000bc651..a23ffc6e0 100644 --- a/Development/nmos/server_utils.cpp +++ b/Development/nmos/server_utils.cpp @@ -61,7 +61,7 @@ namespace nmos ctx.use_certificate_chain(boost::asio::buffer(cert_chain.data(), cert_chain.size())); const auto key_algorithm = server_certificate.key_algorithm; - if (key_algorithm.name.empty() || key_algorithm == key_algorithms::ECDSA) + if (key_algorithm.empty() || key_algorithm == key_algorithms::ECDSA) { // certificates may not have ECDH parameters, so ignore errors... boost::system::error_code ec; diff --git a/Development/nmos/string_enum.h b/Development/nmos/string_enum.h index b564f52ee..c4be7c227 100644 --- a/Development/nmos/string_enum.h +++ b/Development/nmos/string_enum.h @@ -2,12 +2,13 @@ #define NMOS_STRING_ENUM_H #include "cpprest/details/basic_types.h" +#include "nmos/string_enum_fwd.h" namespace nmos { // Many of the JSON fields in the NMOS specifications are strings with an enumerated set of values. // Sometimes these enumerations are extensible (i.e. not a closed set), such as those for media types. - // string_enum is a base class using CRTP to implement type safe enums with simple conversion to string. + // string_enum is a base class using CRTP to implement type-safe enums with simple conversion to string. // See nmos/type.h for a usage example. template struct string_enum @@ -15,6 +16,8 @@ namespace nmos utility::string_t name; // could add explicit string conversion operator? + bool empty() const { return name.empty(); } + // totally_ordered rather than just equality_comparable only to allow use of type as a key // in associative containers; an alternative would be adding a std::hash override so that // unordered associative containers could be used instead? @@ -27,9 +30,7 @@ namespace nmos }; } -#define DECLARE_STRING_ENUM(Type) \ - struct Type; - +// Defines a type-safe extensible string enumeration type #define DEFINE_STRING_ENUM(Type) \ struct Type : public nmos::string_enum \ { \ diff --git a/Development/nmos/string_enum_fwd.h b/Development/nmos/string_enum_fwd.h new file mode 100644 index 000000000..c8f9d4dea --- /dev/null +++ b/Development/nmos/string_enum_fwd.h @@ -0,0 +1,8 @@ +#ifndef NMOS_STRING_ENUM_FWD_H +#define NMOS_STRING_ENUM_FWD_H + +// Declares a type-safe extensible string enumeration type +#define DECLARE_STRING_ENUM(Type) \ + struct Type; + +#endif diff --git a/Development/nmos/test/sdp_utils_test.cpp b/Development/nmos/test/sdp_utils_test.cpp index 06f688504..a2b3db618 100644 --- a/Development/nmos/test/sdp_utils_test.cpp +++ b/Development/nmos/test/sdp_utils_test.cpp @@ -2,8 +2,12 @@ #include "nmos/sdp_utils.h" #include "bst/test/test.h" +#include "nmos/capabilities.h" #include "nmos/components.h" +#include "nmos/format.h" +#include "nmos/interlace_mode.h" #include "nmos/json_fields.h" +#include "nmos/media_type.h" #include "nmos/random.h" #include "sdp/sdp.h" @@ -77,6 +81,175 @@ BST_TEST_CASE(testMakeComponentsMakeSampling) BST_REQUIRE_THROW(nmos::details::make_sampling(test_no_integer_divisor.as_array()), std::logic_error); } +//////////////////////////////////////////////////////////////////////////////////////////// +BST_TEST_CASE(testValidateSdpParameters) +{ + using web::json::value; + using web::json::value_of; + + { + // omitting TCS should be treated as "SDR" + const sdp::transfer_characteristic_system omit_tcs; + + // an unimplemented parameter constraint should be ignored + const utility::string_t unimplemented_parameter_constraint{ U("urn:x-nmos:cap:unimplemented") }; + + nmos::video_raw_parameters params{ + 1920, 1080, nmos::rates::rate29_97, true, false, sdp::samplings::YCbCr_4_2_2, 10, + omit_tcs, sdp::colorimetries::BT2020, sdp::type_parameters::type_N + }; + auto sdp_params = nmos::make_video_raw_sdp_parameters(U("-"), params, nmos::details::payload_type_video_default); + + // only format and caps are used to validate SDP parameters + auto receiver = value_of({ + { nmos::fields::format, nmos::formats::video.name }, + { nmos::fields::caps, value_of({ + { nmos::fields::media_types, value_of({ nmos::media_types::video_raw.name }) }, + { nmos::fields::constraint_sets, value_of({ + value_of({ + { nmos::caps::format::media_type, nmos::make_caps_string_constraint({ nmos::media_types::video_raw.name }) }, + { nmos::caps::format::grain_rate, nmos::make_caps_rational_constraint({ nmos::rates::rate25, nmos::rates::rate29_97 }) }, + { nmos::caps::format::frame_width, nmos::make_caps_integer_constraint({ 1920 }) }, + { nmos::caps::format::frame_height, nmos::make_caps_integer_constraint({ 1080 }) }, + { nmos::caps::format::color_sampling, nmos::make_caps_string_constraint({ sdp::samplings::YCbCr_4_2_2.name }) }, + { nmos::caps::format::interlace_mode, nmos::make_caps_string_constraint({ nmos::interlace_modes::interlaced_bff.name, nmos::interlace_modes::interlaced_tff.name, nmos::interlace_modes::interlaced_psf.name }) }, + { nmos::caps::format::colorspace, nmos::make_caps_string_constraint({ sdp::colorimetries::BT2020.name, sdp::colorimetries::BT709.name }) }, + { nmos::caps::format::transfer_characteristic, nmos::make_caps_string_constraint({ sdp::transfer_characteristic_systems::SDR.name }) }, + { nmos::caps::format::component_depth, nmos::make_caps_integer_constraint({}, 8, 12) }, + { nmos::caps::transport::st2110_21_sender_type, nmos::make_caps_string_constraint({ sdp::type_parameters::type_N.name }) }, + { unimplemented_parameter_constraint, nmos::make_caps_string_constraint({ U("ignored") }) } + }) + }) } + }) } + }); + + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + + receiver[nmos::fields::caps][nmos::fields::media_types] = value_of({ U("foo/meow"), U("foo/purr") }); + BST_REQUIRE_THROW(nmos::validate_sdp_parameters(receiver, sdp_params), std::runtime_error); + + receiver[nmos::fields::caps].erase(nmos::fields::media_types); + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0][nmos::caps::format::media_type] = nmos::make_caps_string_constraint({ U("foo/meow") }); + BST_REQUIRE_THROW(nmos::validate_sdp_parameters(receiver, sdp_params), std::runtime_error); + + // empty parameter constraint is always satisfied + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0][nmos::caps::format::media_type] = value::object(); + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0][nmos::caps::format::grain_rate] = nmos::make_caps_rational_constraint({ nmos::rates::rate50 }); + BST_REQUIRE_THROW(nmos::validate_sdp_parameters(receiver, sdp_params), std::runtime_error); + + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0].erase(nmos::caps::format::grain_rate); + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0][nmos::caps::format::component_depth] = nmos::make_caps_integer_constraint({}, 10); + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0][nmos::caps::format::component_depth] = nmos::make_caps_integer_constraint({}, nmos::no_minimum(), 10); + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0][nmos::caps::format::component_depth] = nmos::make_caps_integer_constraint({}, 10, 10); + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0][nmos::caps::format::component_depth] = nmos::make_caps_integer_constraint({}, 11); + BST_REQUIRE_THROW(nmos::validate_sdp_parameters(receiver, sdp_params), std::runtime_error); + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0][nmos::caps::format::component_depth] = nmos::make_caps_integer_constraint({}, nmos::no_minimum(), 9); + BST_REQUIRE_THROW(nmos::validate_sdp_parameters(receiver, sdp_params), std::runtime_error); + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0][nmos::caps::format::component_depth] = nmos::make_caps_integer_constraint({ 9 }, 8, 12); + BST_REQUIRE_THROW(nmos::validate_sdp_parameters(receiver, sdp_params), std::runtime_error); + + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0].erase(nmos::caps::format::component_depth); + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + + // empty enabled constraint set is always satisfied + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0] = value::object(); + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + + // empty disabled constraint set is not considered and when no constraint set is satisfied, the constraint sets altogether are not satisfied + receiver[nmos::fields::caps][nmos::fields::constraint_sets][0][nmos::caps::meta::enabled] = value::boolean(false); + BST_REQUIRE_THROW(nmos::validate_sdp_parameters(receiver, sdp_params), std::runtime_error); + + // when there are no (enabled) constraint sets, the constraint sets altogether are not satisfied + receiver[nmos::fields::caps][nmos::fields::constraint_sets] = value::array(); + BST_REQUIRE_THROW(nmos::validate_sdp_parameters(receiver, sdp_params), std::runtime_error); + + // when constraint sets aren't in use, that's valid! + receiver[nmos::fields::caps].erase(nmos::fields::constraint_sets); + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + } + + { + nmos::audio_L_parameters params{ 4, 16, 48000, {}, 1 }; + auto sdp_params = nmos::make_audio_L_sdp_parameters(U("-"), params, nmos::details::payload_type_audio_default); + + // only format and caps are used to validate SDP parameters + auto receiver = value_of({ + { nmos::fields::format, nmos::formats::audio.name }, + { nmos::fields::caps, value_of({ + { nmos::fields::media_types, value_of({ nmos::media_types::audio_L(16).name, nmos::media_types::audio_L(24).name }) }, + { nmos::fields::constraint_sets, value_of({ + value_of({ + { nmos::caps::format::media_type, nmos::make_caps_string_constraint({ nmos::media_types::audio_L(16).name }) }, + { nmos::caps::format::channel_count, nmos::make_caps_integer_constraint({}, 1, 8) }, + { nmos::caps::format::sample_rate, nmos::make_caps_rational_constraint({ 48000 }) }, + { nmos::caps::format::sample_depth, nmos::make_caps_integer_constraint({ 16 }) }, + { nmos::caps::transport::packet_time, nmos::make_caps_number_constraint({ 0.125, 1 }) }, + { nmos::caps::transport::max_packet_time, nmos::make_caps_number_constraint({ 0.125, 1 }) } + }), + value_of({ + { nmos::caps::format::media_type, nmos::make_caps_string_constraint({ nmos::media_types::audio_L(24).name }) } + }) + }) } + }) } + }); + + // because the SDP parameters don't include 'maxptime', the 'max_packet_time' parameter constraint will be ignored + + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + + params.channel_count = 16; + sdp_params = nmos::make_audio_L_sdp_parameters(U("-"), params, nmos::details::payload_type_audio_default); + BST_REQUIRE_THROW(nmos::validate_sdp_parameters(receiver, sdp_params), std::runtime_error); + + params.bit_depth = 24; + sdp_params = nmos::make_audio_L_sdp_parameters(U("-"), params, nmos::details::payload_type_audio_default); + BST_REQUIRE_NO_THROW(nmos::validate_sdp_parameters(receiver, sdp_params)); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////// +BST_TEST_CASE(testSdpParametersRoundtrip) +{ + using web::json::value; + + const std::string test_sdp = R"(v=0 +o=- 1643910985 1643910985 IN IP4 192.0.2.0 +s=SDP Example +t=0 0 +m=video 5000 RTP/AVP 96 +c=IN IP4 233.252.0.0/32 +a=source-filter: incl IN IP4 233.252.0.0 192.0.2.0 +a=rtpmap:96 raw/90000 +)"; + + auto test_description = sdp::parse_session_description(test_sdp); + auto params = nmos::parse_session_description(test_description); + params.second[0][nmos::fields::interface_ip] = value::string(U("192.0.2.0")); + auto session_description = nmos::make_session_description(params.first, params.second); + + auto test_sdp2 = sdp::make_session_description(session_description); + std::istringstream expected(test_sdp), actual(test_sdp2); + do + { + std::string expected_line, actual_line; + std::getline(expected, expected_line); + std::getline(actual, actual_line); + // CR cannot appear in a raw string literal, so remove it from the actual line + if (!actual_line.empty() && '\r' == actual_line.back()) actual_line.pop_back(); + BST_CHECK_EQUAL(expected_line, actual_line); + } while (!expected.fail() && !actual.fail()); +} + //////////////////////////////////////////////////////////////////////////////////////////// BST_TEST_CASE(testInterpretationOfSdpFilesUnicast) { diff --git a/Development/sdp/json.h b/Development/sdp/json.h index 4fa250812..9de935beb 100644 --- a/Development/sdp/json.h +++ b/Development/sdp/json.h @@ -154,7 +154,7 @@ namespace sdp const web::json::field payload_type{ U("payload_type") }; const web::json::field_as_string encoding_name{ U("encoding_name") }; const web::json::field clock_rate{ U("clock_rate") }; - const web::json::field_with_default encoding_parameters{ U("encoding_parameters"), 1 }; + const web::json::field_with_default encoding_parameters{ U("encoding_parameters"), 0 }; // a=fmtp: // See https://tools.ietf.org/html/rfc4566#section-6