|
2 | 2 |
|
3 | 3 | #include <limits> |
4 | 4 | #include <boost/algorithm/string/case_conv.hpp> |
| 5 | +#include <boost/algorithm/string/predicate.hpp> |
5 | 6 | #include <boost/asio/ip/address.hpp> |
6 | 7 | #include <boost/range/adaptor/filtered.hpp> |
7 | 8 | #include <boost/range/adaptor/transformed.hpp> |
@@ -955,6 +956,31 @@ namespace nmos |
955 | 956 | return media_type{ sdp_params.media_type.name + U("/") + sdp_params.rtpmap.encoding_name }; |
956 | 957 | } |
957 | 958 |
|
| 959 | + namespace details |
| 960 | + { |
| 961 | + // Find the specified fmtp parameter name case-insensitive in the specified fmtp list per RFC 4855 |
| 962 | + sdp_parameters::fmtp_t::const_iterator find_fmtp(const sdp_parameters::fmtp_t& fmtp, const utility::string_t& name) |
| 963 | + { |
| 964 | + return std::find_if(fmtp.begin(), fmtp.end(), [&](const sdp_parameters::fmtp_t::value_type& param) |
| 965 | + { |
| 966 | + return boost::algorithm::iequals(param.first, name); |
| 967 | + }); |
| 968 | + } |
| 969 | + sdp_parameters::fmtp_t::iterator find_fmtp(sdp_parameters::fmtp_t& fmtp, const utility::string_t& name) |
| 970 | + { |
| 971 | + return std::find_if(fmtp.begin(), fmtp.end(), [&](const sdp_parameters::fmtp_t::value_type& param) |
| 972 | + { |
| 973 | + return boost::algorithm::iequals(param.first, name); |
| 974 | + }); |
| 975 | + } |
| 976 | + |
| 977 | + // RTP encoding names are case-insensitive per RFC 4855 |
| 978 | + bool equals_encoding_name(const utility::string_t& lhs, const utility::string_t& rhs) |
| 979 | + { |
| 980 | + return boost::algorithm::iequals(lhs, rhs); |
| 981 | + } |
| 982 | + } |
| 983 | + |
958 | 984 | web::json::value make_session_description(const sdp_parameters& sdp_params, const web::json::value& transport_params, bst::optional<bool> source_filters) |
959 | 985 | { |
960 | 986 | return make_session_description(sdp_params, transport_params, make_rtpmap(sdp_params), make_fmtp(sdp_params), source_filters); |
@@ -1573,7 +1599,10 @@ namespace nmos |
1573 | 1599 | if (0 == params.channel_count) params.channel_count = 1; |
1574 | 1600 |
|
1575 | 1601 | const auto& encoding_name = sdp_params.rtpmap.encoding_name; |
1576 | | - params.bit_depth = !encoding_name.empty() && U('L') == encoding_name.front() ? utility::istringstreamed<uint32_t>(encoding_name.substr(1)) : 0; |
| 1602 | + // RTP encoding names are case-insensitive per RFC 4855 (e.g. "L24" / "l24") |
| 1603 | + params.bit_depth = !encoding_name.empty() && details::equals_encoding_name(encoding_name.substr(0, 1), U("L")) |
| 1604 | + ? utility::istringstreamed<uint32_t>(encoding_name.substr(1)) |
| 1605 | + : 0; |
1577 | 1606 |
|
1578 | 1607 | params.sample_rate = sdp_params.rtpmap.clock_rate; |
1579 | 1608 |
|
@@ -1674,21 +1703,58 @@ namespace nmos |
1674 | 1703 |
|
1675 | 1704 | namespace details |
1676 | 1705 | { |
| 1706 | + bool is_audio_L_encoding_name(const utility::string_t& encoding_name) |
| 1707 | + { |
| 1708 | + return !encoding_name.empty() && equals_encoding_name(encoding_name.substr(0, 1), U("L")); |
| 1709 | + } |
| 1710 | + |
| 1711 | + // Check the specified media type case-insensitive against enum values in the specified string constraint per RFC 4855 |
| 1712 | + // cf. nmos::match_string_constraint |
| 1713 | + bool match_media_type_constraint(const utility::string_t& value, const web::json::value& constraint) |
| 1714 | + { |
| 1715 | + // first check the enum constraint if present, like nmos::details::match_enum_constraint but with equals_media_type |
| 1716 | + if (constraint.has_field(nmos::fields::constraint_enum)) |
| 1717 | + { |
| 1718 | + const auto& enum_values = nmos::fields::constraint_enum(constraint).as_array(); |
| 1719 | + const media_type actual{ value }; |
| 1720 | + if (enum_values.end() == std::find_if(enum_values.begin(), enum_values.end(), [&](const web::json::value& enum_value) |
| 1721 | + { |
| 1722 | + return enum_value.is_string() && equals_media_type(nmos::media_type{ enum_value.as_string() }, actual); |
| 1723 | + })) |
| 1724 | + { |
| 1725 | + return false; |
| 1726 | + } |
| 1727 | + } |
| 1728 | + // then use nmos::match_string_constraint to check the pattern constraint if present |
| 1729 | + if (constraint.has_field(nmos::fields::constraint_pattern)) |
| 1730 | + { |
| 1731 | + if (!nmos::match_string_constraint(value, web::json::value_of({ |
| 1732 | + { nmos::fields::constraint_pattern, nmos::fields::constraint_pattern(constraint) } |
| 1733 | + }))) |
| 1734 | + { |
| 1735 | + return false; |
| 1736 | + } |
| 1737 | + } |
| 1738 | + return true; |
| 1739 | + } |
| 1740 | + |
1677 | 1741 | nmos::format get_format(const sdp_parameters& sdp_params) |
1678 | 1742 | { |
1679 | | - if (sdp::media_types::video == sdp_params.media_type && U("raw") == sdp_params.rtpmap.encoding_name) return nmos::formats::video; |
1680 | | - if (sdp::media_types::audio == sdp_params.media_type && U("L") == sdp_params.rtpmap.encoding_name.substr(0, 1)) return nmos::formats::audio; |
1681 | | - if (sdp::media_types::video == sdp_params.media_type && U("smpte291") == sdp_params.rtpmap.encoding_name) return nmos::formats::data; |
1682 | | - if (sdp::media_types::video == sdp_params.media_type && U("SMPTE2022-6") == sdp_params.rtpmap.encoding_name) return nmos::formats::mux; |
| 1743 | + const auto& encoding_name = sdp_params.rtpmap.encoding_name; |
| 1744 | + if (sdp::media_types::video == sdp_params.media_type && equals_encoding_name(encoding_name, U("raw"))) return nmos::formats::video; |
| 1745 | + if (sdp::media_types::audio == sdp_params.media_type && is_audio_L_encoding_name(encoding_name)) return nmos::formats::audio; |
| 1746 | + if (sdp::media_types::video == sdp_params.media_type && equals_encoding_name(encoding_name, U("smpte291"))) return nmos::formats::data; |
| 1747 | + if (sdp::media_types::video == sdp_params.media_type && equals_encoding_name(encoding_name, U("SMPTE2022-6"))) return nmos::formats::mux; |
1683 | 1748 | throw sdp_processing_error("unsupported media type/encoding name"); |
1684 | 1749 | } |
1685 | 1750 |
|
1686 | 1751 | format_parameters get_format_parameters(const sdp_parameters& sdp_params) |
1687 | 1752 | { |
1688 | | - if (sdp::media_types::video == sdp_params.media_type && U("raw") == sdp_params.rtpmap.encoding_name) return get_video_raw_parameters(sdp_params); |
1689 | | - if (sdp::media_types::audio == sdp_params.media_type && U("L") == sdp_params.rtpmap.encoding_name.substr(0, 1)) return get_audio_L_parameters(sdp_params); |
1690 | | - if (sdp::media_types::video == sdp_params.media_type && U("smpte291") == sdp_params.rtpmap.encoding_name) return get_video_smpte291_parameters(sdp_params); |
1691 | | - if (sdp::media_types::video == sdp_params.media_type && U("SMPTE2022-6") == sdp_params.rtpmap.encoding_name) return get_video_SMPTE2022_6_parameters(sdp_params); |
| 1753 | + const auto& encoding_name = sdp_params.rtpmap.encoding_name; |
| 1754 | + if (sdp::media_types::video == sdp_params.media_type && equals_encoding_name(encoding_name, U("raw"))) return get_video_raw_parameters(sdp_params); |
| 1755 | + if (sdp::media_types::audio == sdp_params.media_type && is_audio_L_encoding_name(encoding_name)) return get_audio_L_parameters(sdp_params); |
| 1756 | + if (sdp::media_types::video == sdp_params.media_type && equals_encoding_name(encoding_name, U("smpte291"))) return get_video_smpte291_parameters(sdp_params); |
| 1757 | + if (sdp::media_types::video == sdp_params.media_type && equals_encoding_name(encoding_name, U("SMPTE2022-6"))) return get_video_SMPTE2022_6_parameters(sdp_params); |
1692 | 1758 | throw sdp_processing_error("unsupported media type/encoding name"); |
1693 | 1759 | } |
1694 | 1760 |
|
@@ -1723,7 +1789,7 @@ namespace nmos |
1723 | 1789 | { |
1724 | 1790 | // General Constraints |
1725 | 1791 |
|
1726 | | - { nmos::caps::format::media_type, [](CAPS_ARGS) { return nmos::match_string_constraint(get_media_type(sdp).name, con); } }, |
| 1792 | + { nmos::caps::format::media_type, [](CAPS_ARGS) { return match_media_type_constraint(get_media_type(sdp).name, con); } }, |
1727 | 1793 | // hm, how best to match (rational) nmos::caps::format::grain_rate against (double) framerate e.g. for video/SMPTE2022-6? |
1728 | 1794 | // is 23.976 a match for 24000/1001? how about 23.98, or 23.9? or even 23?! |
1729 | 1795 | { nmos::caps::format::grain_rate, [](CAPS_ARGS) { auto exactframerate = get_exactframerate(&format); return nmos::rational{} == exactframerate || nmos::match_rational_constraint(exactframerate, con); } }, |
@@ -1781,7 +1847,10 @@ namespace nmos |
1781 | 1847 | if (!media_types_or_null.is_null()) |
1782 | 1848 | { |
1783 | 1849 | const auto& media_types = media_types_or_null.as_array(); |
1784 | | - const auto found = std::find(media_types.begin(), media_types.end(), web::json::value::string(media_type.name)); |
| 1850 | + const auto found = std::find_if(media_types.begin(), media_types.end(), [&](const web::json::value& candidate) |
| 1851 | + { |
| 1852 | + return candidate.is_string() && equals_media_type(nmos::media_type{ candidate.as_string() }, media_type); |
| 1853 | + }); |
1785 | 1854 | if (media_types.end() == found) throw details::sdp_processing_error("unsupported encoding name"); |
1786 | 1855 | } |
1787 | 1856 | const auto& constraint_sets_or_null = nmos::fields::constraint_sets(caps); |
|
0 commit comments