From cae40b76f4befb31e674cbabfb53b2c556dbf8dd Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley Date: Wed, 20 Oct 2021 08:54:21 +0100 Subject: [PATCH 1/7] Add more missing free functions for web::json::array --- Development/cpprest/json_ops.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Development/cpprest/json_ops.h b/Development/cpprest/json_ops.h index f0e8b81d1..f22c8c409 100644 --- a/Development/cpprest/json_ops.h +++ b/Development/cpprest/json_ops.h @@ -260,6 +260,7 @@ namespace web value.erase(value.size() - 1); } + // deprecated, since pop_front is only found on std containers with fast deletion at the beginning inline void pop_front(web::json::value& value) { value.erase(0); @@ -289,6 +290,29 @@ namespace web { return 0 == value.size(); } + } +} + +// json::array accessors and operations +namespace web +{ + namespace json + { + template + inline void push_back(web::json::array& value, const Value& element) + { + value[value.size()] = web::json::value{ element }; + } + + inline void push_back(web::json::array& value, web::json::value&& element) + { + value[value.size()] = std::move(element); + } + + inline void pop_back(web::json::array& value) + { + value.erase(value.size() - 1); + } inline web::json::value& front(web::json::array& value) { @@ -314,7 +338,14 @@ namespace web { return 0 == value.size(); } + } +} +// json::object accessors and operations +namespace web +{ + namespace json + { inline bool empty(const web::json::object& value) { return value.empty(); From 2adf548af3618f4491ff69256fd70ba66c4ba0bf Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley Date: Wed, 20 Oct 2021 08:56:39 +0100 Subject: [PATCH 2/7] Add make__sdp_parameters to the public interface --- Development/nmos/sdp_utils.cpp | 9 +++++---- Development/nmos/sdp_utils.h | 7 +++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Development/nmos/sdp_utils.cpp b/Development/nmos/sdp_utils.cpp index 6774f5035..3a6a939b5 100644 --- a/Development/nmos/sdp_utils.cpp +++ b/Development/nmos/sdp_utils.cpp @@ -136,7 +136,7 @@ namespace nmos } } - static sdp_parameters make_video_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_video_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) { sdp_parameters::video_t params; params.tp = sdp::type_parameters::type_N; @@ -167,7 +167,7 @@ namespace nmos return{ sender.at(nmos::fields::label).as_string(), params, 96, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - static sdp_parameters make_audio_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_audio_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) { sdp_parameters::audio_t params; @@ -192,7 +192,7 @@ namespace nmos return{ sender.at(nmos::fields::label).as_string(), params, 97, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - static sdp_parameters make_data_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_data_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) { sdp_parameters::data_t params; @@ -209,7 +209,7 @@ namespace nmos return{ sender.at(nmos::fields::label).as_string(), params, 100, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - static sdp_parameters make_mux_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_mux_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) { sdp_parameters::mux_t params; // "Senders shall comply with either the Narrow Linear Senders (Type NL) requirements, or the Wide Senders (Type W) requirements." @@ -222,6 +222,7 @@ namespace nmos return{ sender.at(nmos::fields::label).as_string(), params, 98, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } + // Construct SDP parameters from the IS-04 resources sdp_parameters make_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) { const auto& format = nmos::fields::format(flow); diff --git a/Development/nmos/sdp_utils.h b/Development/nmos/sdp_utils.h index 7b84b181b..322339f42 100644 --- a/Development/nmos/sdp_utils.h +++ b/Development/nmos/sdp_utils.h @@ -20,11 +20,18 @@ namespace nmos sdp::sampling make_sampling(const web::json::array& components); } + // Construct SDP parameters from the IS-04 resources sdp_parameters make_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); // deprecated, provided for backwards compatibility, because it may be necessary to also specify the PTP domain to generate an RFC 7273 'ts-refclk' attribute that meets the additional constraints of ST 2110-10 sdp_parameters make_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids); + // Construct SDP parameters for the specified format from the IS-04 resources + sdp_parameters make_video_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); + sdp_parameters make_audio_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); + sdp_parameters make_data_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); + sdp_parameters make_mux_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); + // Sender/Receiver helper functions // Make a json representation of an SDP file, e.g. for sdp::make_session_description, from the specified parameters; explicitly specify whether 'source-filter' attributes are included to override the default behaviour From cb8615c240041b2f94656e254e7436e4a2f4c8aa Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley Date: Wed, 20 Oct 2021 09:20:17 +0100 Subject: [PATCH 3/7] Allow payload type to be specified to the make__sdp_parameters functions --- Development/nmos/sdp_utils.cpp | 26 +++++++++++++------------- Development/nmos/sdp_utils.h | 12 ++++++------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Development/nmos/sdp_utils.cpp b/Development/nmos/sdp_utils.cpp index 3a6a939b5..a00a48b63 100644 --- a/Development/nmos/sdp_utils.cpp +++ b/Development/nmos/sdp_utils.cpp @@ -136,7 +136,7 @@ namespace nmos } } - sdp_parameters make_video_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_video_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) { sdp_parameters::video_t params; params.tp = sdp::type_parameters::type_N; @@ -164,10 +164,10 @@ namespace nmos const auto& grain_rate = nmos::fields::grain_rate(flow.has_field(nmos::fields::grain_rate) ? flow : source); params.exactframerate = nmos::rational(nmos::fields::numerator(grain_rate), nmos::fields::denominator(grain_rate)); - return{ sender.at(nmos::fields::label).as_string(), params, 96, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 96, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - sdp_parameters make_audio_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_audio_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) { sdp_parameters::audio_t params; @@ -189,10 +189,10 @@ namespace nmos // ptime params.packet_time = 1; - return{ sender.at(nmos::fields::label).as_string(), params, 97, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 97, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - sdp_parameters make_data_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_data_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) { sdp_parameters::data_t params; @@ -206,10 +206,10 @@ namespace nmos // hm, no vpid_code in the flow - return{ sender.at(nmos::fields::label).as_string(), params, 100, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 100, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - sdp_parameters make_mux_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_mux_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) { sdp_parameters::mux_t params; // "Senders shall comply with either the Narrow Linear Senders (Type NL) requirements, or the Wide Senders (Type W) requirements." @@ -219,21 +219,21 @@ namespace nmos // Payload type 98 is "High bit rate media transport / 27-MHz Clock" // Payload type 99 is "High bit rate media transport FEC / 27-MHz Clock" // See SMPTE ST 2022-6:2012 Section 6.3 RTP/UDP/IP Header - return{ sender.at(nmos::fields::label).as_string(), params, 98, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 98, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - // Construct SDP parameters from the IS-04 resources + // Construct SDP parameters from the IS-04 resources, using a default payload type sdp_parameters make_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) { const auto& format = nmos::fields::format(flow); if (nmos::formats::video.name == format) - return make_video_sdp_parameters(node, source, flow, sender, media_stream_ids, ptp_domain); + return make_video_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain); else if (nmos::formats::audio.name == format) - return make_audio_sdp_parameters(node, source, flow, sender, media_stream_ids, ptp_domain); + return make_audio_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain); else if (nmos::formats::data.name == format) - return make_data_sdp_parameters(node, source, flow, sender, media_stream_ids, ptp_domain); + return make_data_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain); else if (nmos::formats::mux.name == format) - return make_mux_sdp_parameters(node, source, flow, sender, media_stream_ids, ptp_domain); + return make_mux_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain); else throw details::sdp_creation_error("unsuported media format"); } diff --git a/Development/nmos/sdp_utils.h b/Development/nmos/sdp_utils.h index 322339f42..0b1347e8a 100644 --- a/Development/nmos/sdp_utils.h +++ b/Development/nmos/sdp_utils.h @@ -20,17 +20,17 @@ namespace nmos sdp::sampling make_sampling(const web::json::array& components); } - // Construct SDP parameters from the IS-04 resources + // Construct SDP parameters from the IS-04 resources, using a default payload type sdp_parameters make_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); // deprecated, provided for backwards compatibility, because it may be necessary to also specify the PTP domain to generate an RFC 7273 'ts-refclk' attribute that meets the additional constraints of ST 2110-10 sdp_parameters make_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids); - // Construct SDP parameters for the specified format from the IS-04 resources - sdp_parameters make_video_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); - sdp_parameters make_audio_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); - sdp_parameters make_data_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); - sdp_parameters make_mux_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); + // Construct SDP parameters for the specified format from the IS-04 resources, using a default payload type if not specified + sdp_parameters make_video_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); + sdp_parameters make_audio_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); + sdp_parameters make_data_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); + sdp_parameters make_mux_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); // Sender/Receiver helper functions From a3f2b1216a58de445088885368d5d10ad7a50db6 Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley Date: Wed, 20 Oct 2021 09:39:44 +0100 Subject: [PATCH 4/7] Update Video Payload IP Codes from https://smpte-ra.org/video-payload-id-codes-serial-digital-interfaces --- Development/nmos/vpid_code.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Development/nmos/vpid_code.h b/Development/nmos/vpid_code.h index eb3519088..96dec8ad7 100644 --- a/Development/nmos/vpid_code.h +++ b/Development/nmos/vpid_code.h @@ -13,14 +13,16 @@ namespace nmos // See https://smpte-ra.org/video-payload-id-codes-serial-digital-interfaces namespace vpid_codes { - // 483/576-line interlaced payloads on 270 Mb/s and 360 Mb/s serial digital interfaces + // 483/576-line interlaced video payloads on 270 Mb/s and 360 Mb/s serial digital interfaces const vpid_code vpid_270Mbps = 129; - // 483/576-line extended payloads on 360 Mb/s single-link and 270 Mb/s dual-link serial digital interfaces + // 483/576-line extended video payloads on 360 Mb/s single-link and 270 Mb/s dual-link serial digital interfaces const vpid_code vpid_360Mbps = 130; - // 483/576-line payloads on a 540 Mb/s serial digital interface + // 483/576-line video payloads on a 540 Mb/s serial digital interface const vpid_code vpid_540Mbps = 131; - // 483/576-line payloads on a 1.485 Gb/s (nominal) serial digital interface - const vpid_code vpid_1_5Gbps = 132; + // 720-line video payloads on a 1.5 Gb/s (nominal) serial digital interface + const vpid_code vpid_1_5Gbps_720_line = 132; + // 1080-line video payloads on a 1.5 Gb/s (nominal) serial digital interface + const vpid_code vpid_1_5Gbps_1080_line = 133; // extensible enum } From 9f077dd096b6949afbb8b16f8b35e3c485dc33ae Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley Date: Wed, 20 Oct 2021 09:57:01 +0100 Subject: [PATCH 5/7] Allow the most important previously defaulted values to be specified explicitly in the make__sdp_parameters functions: ST 2110-21 Type Parameter for video/mux, packet time for ST 2110-30 audio and VPID Code for ST 2110-40 ancillary data --- Development/nmos/sdp_utils.cpp | 27 ++++++++++++++------------- Development/nmos/sdp_utils.h | 12 ++++++------ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/Development/nmos/sdp_utils.cpp b/Development/nmos/sdp_utils.cpp index a00a48b63..e80915bf6 100644 --- a/Development/nmos/sdp_utils.cpp +++ b/Development/nmos/sdp_utils.cpp @@ -136,10 +136,10 @@ namespace nmos } } - sdp_parameters make_video_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_video_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp) { sdp_parameters::video_t params; - params.tp = sdp::type_parameters::type_N; + params.tp = tp ? *tp : sdp::type_parameters::type_N; // colorimetry map directly to flow_video json "colorspace" params.colorimetry = sdp::colorimetry{ nmos::fields::colorspace(flow) }; @@ -167,7 +167,7 @@ namespace nmos return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 96, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - sdp_parameters make_audio_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_audio_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional packet_time) { sdp_parameters::audio_t params; @@ -187,12 +187,12 @@ namespace nmos params.channel_order = nmos::make_fmtp_channel_order(channel_symbols); // ptime - params.packet_time = 1; + params.packet_time = packet_time ? *packet_time : 1; return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 97, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - sdp_parameters make_data_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_data_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional vpid_code) { sdp_parameters::data_t params; @@ -205,16 +205,17 @@ namespace nmos })); // hm, no vpid_code in the flow + params.vpid_code = vpid_code ? *vpid_code : 0; return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 100, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - sdp_parameters make_mux_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) + sdp_parameters make_mux_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp) { sdp_parameters::mux_t params; // "Senders shall comply with either the Narrow Linear Senders (Type NL) requirements, or the Wide Senders (Type W) requirements." // See SMPTE ST 2022-8:2019 Section 6 Network Compatibility and Transmission Traffic Shape Models - params.tp = sdp::type_parameters::type_NL; + params.tp = tp ? *tp : sdp::type_parameters::type_NL; // Payload type 98 is "High bit rate media transport / 27-MHz Clock" // Payload type 99 is "High bit rate media transport FEC / 27-MHz Clock" @@ -222,20 +223,20 @@ namespace nmos return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 98, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - // Construct SDP parameters from the IS-04 resources, using a default payload type + // Construct SDP parameters from the IS-04 resources, using default values for unspecified items sdp_parameters make_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain) { const auto& format = nmos::fields::format(flow); if (nmos::formats::video.name == format) - return make_video_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain); + return make_video_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain, {}); else if (nmos::formats::audio.name == format) - return make_audio_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain); + return make_audio_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain, {}); else if (nmos::formats::data.name == format) - return make_data_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain); + return make_data_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain, {}); else if (nmos::formats::mux.name == format) - return make_mux_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain); + return make_mux_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain, {}); else - throw details::sdp_creation_error("unsuported media format"); + throw details::sdp_creation_error("unsupported media format"); } // deprecated, provided for backwards compatibility, because it may be necessary to also specify the PTP domain to generate an RFC 7273 'ts-refclk' attribute that meets the additional constraints of ST 2110-10 diff --git a/Development/nmos/sdp_utils.h b/Development/nmos/sdp_utils.h index 0b1347e8a..9c7be75e3 100644 --- a/Development/nmos/sdp_utils.h +++ b/Development/nmos/sdp_utils.h @@ -20,17 +20,17 @@ namespace nmos sdp::sampling make_sampling(const web::json::array& components); } - // Construct SDP parameters from the IS-04 resources, using a default payload type + // Construct SDP parameters from the IS-04 resources, using default values for unspecified items sdp_parameters make_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); // deprecated, provided for backwards compatibility, because it may be necessary to also specify the PTP domain to generate an RFC 7273 'ts-refclk' attribute that meets the additional constraints of ST 2110-10 sdp_parameters make_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids); - // Construct SDP parameters for the specified format from the IS-04 resources, using a default payload type if not specified - sdp_parameters make_video_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); - sdp_parameters make_audio_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); - sdp_parameters make_data_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); - sdp_parameters make_mux_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain); + // Construct SDP parameters for the specified format from the IS-04 resources, using default values for unspecified items + sdp_parameters make_video_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp); + sdp_parameters make_audio_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional packet_time); + sdp_parameters make_data_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional vpid_code); + sdp_parameters make_mux_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp); // Sender/Receiver helper functions From ac9987416e58343f6ac870bcb9eefba66e55f21b Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley Date: Wed, 20 Oct 2021 18:40:28 +0100 Subject: [PATCH 6/7] Move optional payload_type to beginning of optional args and add links to RFC 3551, etc. --- Development/nmos/sdp_utils.cpp | 45 ++++++++++++++++++++++------------ Development/nmos/sdp_utils.h | 8 +++--- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/Development/nmos/sdp_utils.cpp b/Development/nmos/sdp_utils.cpp index e80915bf6..b94f59794 100644 --- a/Development/nmos/sdp_utils.cpp +++ b/Development/nmos/sdp_utils.cpp @@ -136,7 +136,23 @@ namespace nmos } } - sdp_parameters make_video_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp) + namespace details + { + // Payload identifiers 96-127 are used for payloads defined dynamically during a session + // 96 and 97 are suitable for video and audio encodings not covered by the IANA registry + // See https://tools.ietf.org/html/rfc3551#section-3 + // and https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-1 + const uint64_t payload_type_video_default = 96; + const uint64_t payload_type_audio_default = 97; + const uint64_t payload_type_data_default = 100; + // Payload type 98 is recommended for "High bit rate media transport / 27-MHz Clock" + // Payload type 99 is recommended for "High bit rate media transport FEC / 27-MHz Clock" + // "Alternatively, payload types may be set by other means in accordance with RFC 3550." + // See SMPTE ST 2022-6:2012 Section 6.3 RTP/UDP/IP Header + const uint64_t payload_type_mux_default = 98; + } + + sdp_parameters make_video_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp) { sdp_parameters::video_t params; params.tp = tp ? *tp : sdp::type_parameters::type_N; @@ -164,10 +180,10 @@ namespace nmos const auto& grain_rate = nmos::fields::grain_rate(flow.has_field(nmos::fields::grain_rate) ? flow : source); params.exactframerate = nmos::rational(nmos::fields::numerator(grain_rate), nmos::fields::denominator(grain_rate)); - return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 96, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_video_default, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - sdp_parameters make_audio_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional packet_time) + sdp_parameters make_audio_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional packet_time) { sdp_parameters::audio_t params; @@ -186,13 +202,13 @@ namespace nmos })); params.channel_order = nmos::make_fmtp_channel_order(channel_symbols); - // ptime + // ptime, e.g. 1 ms or 0.125 ms params.packet_time = packet_time ? *packet_time : 1; - return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 97, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_audio_default, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - sdp_parameters make_data_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional vpid_code) + sdp_parameters make_data_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional vpid_code) { sdp_parameters::data_t params; @@ -207,20 +223,17 @@ namespace nmos // hm, no vpid_code in the flow params.vpid_code = vpid_code ? *vpid_code : 0; - return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 100, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_data_default, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } - sdp_parameters make_mux_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp) + sdp_parameters make_mux_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp) { sdp_parameters::mux_t params; // "Senders shall comply with either the Narrow Linear Senders (Type NL) requirements, or the Wide Senders (Type W) requirements." // See SMPTE ST 2022-8:2019 Section 6 Network Compatibility and Transmission Traffic Shape Models params.tp = tp ? *tp : sdp::type_parameters::type_NL; - // Payload type 98 is "High bit rate media transport / 27-MHz Clock" - // Payload type 99 is "High bit rate media transport FEC / 27-MHz Clock" - // See SMPTE ST 2022-6:2012 Section 6.3 RTP/UDP/IP Header - return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : 98, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_mux_default, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; } // Construct SDP parameters from the IS-04 resources, using default values for unspecified items @@ -228,13 +241,13 @@ namespace nmos { const auto& format = nmos::fields::format(flow); if (nmos::formats::video.name == format) - return make_video_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain, {}); + return make_video_sdp_parameters(node, source, flow, sender, {}, media_stream_ids, ptp_domain, {}); else if (nmos::formats::audio.name == format) - return make_audio_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain, {}); + return make_audio_sdp_parameters(node, source, flow, sender, {}, media_stream_ids, ptp_domain, {}); else if (nmos::formats::data.name == format) - return make_data_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain, {}); + return make_data_sdp_parameters(node, source, flow, sender, {}, media_stream_ids, ptp_domain, {}); else if (nmos::formats::mux.name == format) - return make_mux_sdp_parameters({}, node, source, flow, sender, media_stream_ids, ptp_domain, {}); + return make_mux_sdp_parameters(node, source, flow, sender, {}, media_stream_ids, ptp_domain, {}); else throw details::sdp_creation_error("unsupported media format"); } diff --git a/Development/nmos/sdp_utils.h b/Development/nmos/sdp_utils.h index 9c7be75e3..d77aed89a 100644 --- a/Development/nmos/sdp_utils.h +++ b/Development/nmos/sdp_utils.h @@ -27,10 +27,10 @@ namespace nmos sdp_parameters make_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids); // Construct SDP parameters for the specified format from the IS-04 resources, using default values for unspecified items - sdp_parameters make_video_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp); - sdp_parameters make_audio_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional packet_time); - sdp_parameters make_data_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional vpid_code); - sdp_parameters make_mux_sdp_parameters(bst::optional payload_type, const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp); + sdp_parameters make_video_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp); + sdp_parameters make_audio_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional packet_time); + sdp_parameters make_data_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional vpid_code); + sdp_parameters make_mux_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp); // Sender/Receiver helper functions From 69a515b3ec7221ed606ebde4ea87e7e20fa68e17 Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley Date: Wed, 20 Oct 2021 19:30:05 +0100 Subject: [PATCH 7/7] Implement default media stream ids based on the sender's number of legs --- Development/nmos/sdp_utils.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Development/nmos/sdp_utils.cpp b/Development/nmos/sdp_utils.cpp index b94f59794..bdf9aeb87 100644 --- a/Development/nmos/sdp_utils.cpp +++ b/Development/nmos/sdp_utils.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "cpprest/basic_utils.h" #include "nmos/capabilities.h" #include "nmos/clock_ref_type.h" @@ -134,10 +135,7 @@ namespace nmos } else throw sdp_creation_error("unsupported components"); } - } - namespace details - { // Payload identifiers 96-127 are used for payloads defined dynamically during a session // 96 and 97 are suitable for video and audio encodings not covered by the IANA registry // See https://tools.ietf.org/html/rfc3551#section-3 @@ -150,6 +148,16 @@ namespace nmos // "Alternatively, payload types may be set by other means in accordance with RFC 3550." // See SMPTE ST 2022-6:2012 Section 6.3 RTP/UDP/IP Header const uint64_t payload_type_mux_default = 98; + + // make simple media stream ids based on the sender's number of legs + std::vector make_media_stream_ids(const web::json::value& sender) + { + const auto legs = nmos::fields::interface_bindings(sender).size(); + return boost::copy_range>(boost::irange(0, (int)legs) | boost::adaptors::transformed([&](const int& index) + { + return utility::ostringstreamed(index); + })); + } } sdp_parameters make_video_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp) @@ -180,7 +188,7 @@ namespace nmos const auto& grain_rate = nmos::fields::grain_rate(flow.has_field(nmos::fields::grain_rate) ? flow : source); params.exactframerate = nmos::rational(nmos::fields::numerator(grain_rate), nmos::fields::denominator(grain_rate)); - return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_video_default, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_video_default, !media_stream_ids.empty() ? media_stream_ids : details::make_media_stream_ids(sender), details::make_ts_refclk(node, source, sender, ptp_domain) }; } sdp_parameters make_audio_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional packet_time) @@ -205,7 +213,7 @@ namespace nmos // ptime, e.g. 1 ms or 0.125 ms params.packet_time = packet_time ? *packet_time : 1; - return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_audio_default, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_audio_default, !media_stream_ids.empty() ? media_stream_ids : details::make_media_stream_ids(sender), details::make_ts_refclk(node, source, sender, ptp_domain) }; } sdp_parameters make_data_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional vpid_code) @@ -223,7 +231,7 @@ namespace nmos // hm, no vpid_code in the flow params.vpid_code = vpid_code ? *vpid_code : 0; - return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_data_default, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_data_default, !media_stream_ids.empty() ? media_stream_ids : details::make_media_stream_ids(sender), details::make_ts_refclk(node, source, sender, ptp_domain) }; } sdp_parameters make_mux_sdp_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional payload_type, const std::vector& media_stream_ids, bst::optional ptp_domain, bst::optional tp) @@ -233,7 +241,7 @@ namespace nmos // See SMPTE ST 2022-8:2019 Section 6 Network Compatibility and Transmission Traffic Shape Models params.tp = tp ? *tp : sdp::type_parameters::type_NL; - return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_mux_default, media_stream_ids, details::make_ts_refclk(node, source, sender, ptp_domain) }; + return{ sender.at(nmos::fields::label).as_string(), params, payload_type ? *payload_type : details::payload_type_mux_default, !media_stream_ids.empty() ? media_stream_ids : details::make_media_stream_ids(sender), details::make_ts_refclk(node, source, sender, ptp_domain) }; } // Construct SDP parameters from the IS-04 resources, using default values for unspecified items