Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions Development/cmake/NmosCppTest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ set(NMOS_CPP_TEST_NMOS_TEST_SOURCES
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 Down
185 changes: 176 additions & 9 deletions Development/nmos/connection_resources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,70 @@ namespace nmos
});
}

web::json::value make_connection_rtp_sender_fec_constraints()
{
using web::json::value;
using web::json::value_of;

const auto unconstrained = value::object();
return value_of({
{ nmos::fields::fec_enabled, unconstrained },
{ nmos::fields::fec_destination_ip, unconstrained },
{ nmos::fields::fec_type, unconstrained },
{ nmos::fields::fec_mode, unconstrained },
{ nmos::fields::fec_block_width, unconstrained },
{ nmos::fields::fec_block_height, unconstrained },
{ nmos::fields::fec1D_destination_port, unconstrained },
{ nmos::fields::fec2D_destination_port, unconstrained },
{ nmos::fields::fec1D_source_port, unconstrained },
{ nmos::fields::fec2D_source_port, unconstrained }
});
}

web::json::value make_connection_rtp_sender_staged_fec_parameter_set()
{
using web::json::value_of;

return value_of({
{ nmos::fields::fec_enabled, false },
{ nmos::fields::fec_destination_ip, U("auto") },
{ nmos::fields::fec_type, U("XOR") },
{ nmos::fields::fec_mode, U("1D") },
{ nmos::fields::fec_block_width, 4 },
{ nmos::fields::fec_block_height, 4 },
{ nmos::fields::fec1D_destination_port, U("auto") },
{ nmos::fields::fec2D_destination_port, U("auto") },
{ nmos::fields::fec1D_source_port, U("auto") },
{ nmos::fields::fec2D_source_port, U("auto") }
});
}

web::json::value make_connection_rtp_sender_rtcp_constraints()
{
using web::json::value;
using web::json::value_of;

const auto unconstrained = value::object();
return value_of({
{ nmos::fields::rtcp_enabled, unconstrained },
{ nmos::fields::rtcp_destination_ip, unconstrained },
{ nmos::fields::rtcp_destination_port, unconstrained },
{ nmos::fields::rtcp_source_port, unconstrained }
});
}

web::json::value make_connection_rtp_sender_staged_rtcp_parameter_set()
{
using web::json::value_of;

return value_of({
{ nmos::fields::rtcp_enabled, false },
{ nmos::fields::rtcp_destination_ip, U("auto") },
{ nmos::fields::rtcp_destination_port, U("auto") },
{ nmos::fields::rtcp_source_port, U("auto") }
});
}

// See https://specs.amwa.tv/is-05/releases/v1.1.0/docs/4.1._Behaviour_-_RTP_Transport_Type.html#receiver-parameter-sets
// and https://specs.amwa.tv/is-05/releases/v1.1.0/APIs/schemas/with-refs/constraints-schema-rtp.html
web::json::value make_connection_rtp_receiver_core_constraints()
Expand All @@ -122,8 +186,7 @@ namespace nmos
{ nmos::fields::source_ip, unconstrained },
{ nmos::fields::interface_ip, unconstrained },
{ nmos::fields::destination_port, unconstrained },
{ nmos::fields::rtp_enabled, unconstrained },
{ nmos::fields::multicast_ip, unconstrained }
{ nmos::fields::rtp_enabled, unconstrained }
});
}

Expand All @@ -138,23 +201,109 @@ namespace nmos
{ nmos::fields::source_ip, value::null() },
{ nmos::fields::interface_ip, U("auto") },
{ nmos::fields::destination_port, U("auto") },
{ nmos::fields::rtp_enabled, true },
{ nmos::fields::rtp_enabled, true }
});
}

web::json::value make_connection_rtp_receiver_multicast_constraints()
{
using web::json::value;
using web::json::value_of;

return value_of({
{ nmos::fields::multicast_ip, value::object() }
});
}

web::json::value make_connection_rtp_receiver_staged_multicast_parameter_set()
{
using web::json::value;
using web::json::value_of;

return value_of({
{ nmos::fields::multicast_ip, value::null() }
});
}

web::json::value make_connection_rtp_receiver_fec_constraints()
{
using web::json::value;
using web::json::value_of;

const auto unconstrained = value::object();
return value_of({
{ nmos::fields::fec_enabled, unconstrained },
{ nmos::fields::fec_destination_ip, unconstrained },
{ nmos::fields::fec_mode, unconstrained },
{ nmos::fields::fec1D_destination_port, unconstrained },
{ nmos::fields::fec2D_destination_port, unconstrained }
});
}

web::json::value make_connection_rtp_receiver_staged_fec_parameter_set()
{
using web::json::value_of;

return value_of({
{ nmos::fields::fec_enabled, false },
{ nmos::fields::fec_destination_ip, U("auto") },
{ nmos::fields::fec_mode, U("auto") },
{ nmos::fields::fec1D_destination_port, U("auto") },
{ nmos::fields::fec2D_destination_port, U("auto") }
});
}

web::json::value make_connection_rtp_receiver_rtcp_constraints()
{
using web::json::value;
using web::json::value_of;

const auto unconstrained = value::object();
return value_of({
{ nmos::fields::rtcp_enabled, unconstrained },
{ nmos::fields::rtcp_destination_ip, unconstrained },
{ nmos::fields::rtcp_destination_port, unconstrained }
});
}

web::json::value make_connection_rtp_receiver_staged_rtcp_parameter_set()
{
using web::json::value_of;

return value_of({
{ nmos::fields::rtcp_enabled, false },
{ nmos::fields::rtcp_destination_ip, U("auto") },
{ nmos::fields::rtcp_destination_port, U("auto") }
});
}

void insert_parameter_set(web::json::value& parameters, const web::json::value& parameter_set)
{
web::json::insert(parameters, parameter_set.as_object().begin(), parameter_set.as_object().end());
}
}

nmos::resource make_connection_rtp_sender(const nmos::id& id, bool smpte2022_7)
{
return make_connection_rtp_sender(id, smpte2022_7, rtp_sender_parameter_sets{});
}

nmos::resource make_connection_rtp_sender(const nmos::id& id, bool smpte2022_7, const rtp_sender_parameter_sets& parameter_sets)
{
using web::json::value;
using web::json::value_of;

auto data = details::make_connection_resource_core(id, smpte2022_7);

data[nmos::fields::endpoint_constraints] = details::legs_of(details::make_connection_rtp_sender_core_constraints(), smpte2022_7);
auto constraints = details::make_connection_rtp_sender_core_constraints();
if (parameter_sets.fec) details::insert_parameter_set(constraints, details::make_connection_rtp_sender_fec_constraints());
if (parameter_sets.rtcp) details::insert_parameter_set(constraints, details::make_connection_rtp_sender_rtcp_constraints());
data[nmos::fields::endpoint_constraints] = details::legs_of(constraints, smpte2022_7);

data[nmos::fields::endpoint_staged][nmos::fields::receiver_id] = value::null();
data[nmos::fields::endpoint_staged][nmos::fields::transport_params] = details::legs_of(details::make_connection_rtp_sender_staged_core_parameter_set(), smpte2022_7);
auto transport_params = details::make_connection_rtp_sender_staged_core_parameter_set();
if (parameter_sets.fec) details::insert_parameter_set(transport_params, details::make_connection_rtp_sender_staged_fec_parameter_set());
if (parameter_sets.rtcp) details::insert_parameter_set(transport_params, details::make_connection_rtp_sender_staged_rtcp_parameter_set());
data[nmos::fields::endpoint_staged][nmos::fields::transport_params] = details::legs_of(transport_params, smpte2022_7);

data[nmos::fields::endpoint_active] = data[nmos::fields::endpoint_staged];
// The caller must resolve all instances of "auto" in the /active endpoint into the actual values that will be used!
Expand Down Expand Up @@ -188,7 +337,12 @@ namespace nmos

nmos::resource make_connection_rtp_sender(const nmos::id& id, bool smpte2022_7, const utility::string_t& transportfile)
{
auto resource = make_connection_rtp_sender(id, smpte2022_7);
return make_connection_rtp_sender(id, smpte2022_7, rtp_sender_parameter_sets{}, transportfile);
}

nmos::resource make_connection_rtp_sender(const nmos::id& id, bool smpte2022_7, const rtp_sender_parameter_sets& parameter_sets, const utility::string_t& transportfile)
{
auto resource = make_connection_rtp_sender(id, smpte2022_7, parameter_sets);

const utility::string_t sdp_magic(U("v=0"));

Expand All @@ -204,16 +358,29 @@ namespace nmos
}

nmos::resource make_connection_rtp_receiver(const nmos::id& id, bool smpte2022_7)
{
return make_connection_rtp_receiver(id, smpte2022_7, rtp_receiver_parameter_sets{});
}

nmos::resource make_connection_rtp_receiver(const nmos::id& id, bool smpte2022_7, const rtp_receiver_parameter_sets& parameter_sets)
{
using web::json::value;

auto data = details::make_connection_resource_core(id, smpte2022_7);

data[nmos::fields::endpoint_constraints] = details::legs_of(details::make_connection_rtp_receiver_core_constraints(), smpte2022_7);
auto constraints = details::make_connection_rtp_receiver_core_constraints();
if (parameter_sets.multicast) details::insert_parameter_set(constraints, details::make_connection_rtp_receiver_multicast_constraints());
if (parameter_sets.fec) details::insert_parameter_set(constraints, details::make_connection_rtp_receiver_fec_constraints());
if (parameter_sets.rtcp) details::insert_parameter_set(constraints, details::make_connection_rtp_receiver_rtcp_constraints());
data[nmos::fields::endpoint_constraints] = details::legs_of(constraints, smpte2022_7);

data[nmos::fields::endpoint_staged][nmos::fields::sender_id] = value::null();
data[nmos::fields::endpoint_staged][nmos::fields::transport_file] = details::make_connection_receiver_staging_transport_file();
data[nmos::fields::endpoint_staged][nmos::fields::transport_params] = details::legs_of(details::make_connection_rtp_receiver_staged_core_parameter_set(), smpte2022_7);
auto transport_params = details::make_connection_rtp_receiver_staged_core_parameter_set();
if (parameter_sets.multicast) details::insert_parameter_set(transport_params, details::make_connection_rtp_receiver_staged_multicast_parameter_set());
if (parameter_sets.fec) details::insert_parameter_set(transport_params, details::make_connection_rtp_receiver_staged_fec_parameter_set());
if (parameter_sets.rtcp) details::insert_parameter_set(transport_params, details::make_connection_rtp_receiver_staged_rtcp_parameter_set());
data[nmos::fields::endpoint_staged][nmos::fields::transport_params] = details::legs_of(transport_params, smpte2022_7);

data[nmos::fields::endpoint_active] = data[nmos::fields::endpoint_staged];
// The caller must resolve all instances of "auto" in the /active endpoint into the actual values that will be used!
Expand Down
29 changes: 29 additions & 0 deletions Development/nmos/connection_resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,32 @@ namespace nmos
{
struct resource;

// Optional IS-05 RTP parameter sets supported by a Sender or Receiver.
// Core parameters are mandatory and therefore not represented by these types.
struct rtp_sender_parameter_sets
{
bool fec;
bool rtcp;

explicit rtp_sender_parameter_sets(bool fec = false, bool rtcp = false)
: fec(fec)
, rtcp(rtcp)
{}
};

struct rtp_receiver_parameter_sets
{
bool multicast;
bool fec;
bool rtcp;

explicit rtp_receiver_parameter_sets(bool multicast = true, bool fec = false, bool rtcp = false)
: multicast(multicast)
, fec(fec)
, rtcp(rtcp)
{}
};

// make an absolute URL for the /transportfile endpoint of the specified sender
// e.g. for use in the manifest_href property of the IS-04 Node API sender
web::uri make_connection_api_transportfile(const nmos::id& sender_id, const nmos::settings& settings);
Expand All @@ -36,6 +62,7 @@ namespace nmos
// The caller must resolve all instances of "auto" in the /active endpoint into the actual values that will be used!
// See nmos::resolve_rtp_auto
nmos::resource make_connection_rtp_sender(const nmos::id& id, bool smpte2022_7);
nmos::resource make_connection_rtp_sender(const nmos::id& id, bool smpte2022_7, const rtp_sender_parameter_sets& parameter_sets);

web::json::value make_connection_rtp_sender_transportfile(const utility::string_t& transportfile);
web::json::value make_connection_rtp_sender_transportfile(const web::uri& transportfile);
Expand All @@ -44,10 +71,12 @@ namespace nmos
// See nmos::resolve_rtp_auto
// transportfile may be URL or the contents of the SDP file (yeah, yuck)
nmos::resource make_connection_rtp_sender(const nmos::id& id, bool smpte2022_7, const utility::string_t& transportfile);
nmos::resource make_connection_rtp_sender(const nmos::id& id, bool smpte2022_7, const rtp_sender_parameter_sets& parameter_sets, const utility::string_t& transportfile);

// The caller must resolve all instances of "auto" in the /active endpoint into the actual values that will be used!
// See nmos::resolve_rtp_auto
nmos::resource make_connection_rtp_receiver(const nmos::id& id, bool smpte2022_7);
nmos::resource make_connection_rtp_receiver(const nmos::id& id, bool smpte2022_7, const rtp_receiver_parameter_sets& parameter_sets);

// Although these functions make "connection" (IS-05) resources, the details are defined by IS-07 Event & Tally
// so maybe these belong in nmos/events_resources.h or their own file, e.g. nmos/connection_events_resources.h?
Expand Down
7 changes: 6 additions & 1 deletion Development/nmos/json_fields.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,20 @@ namespace nmos
const web::json::field_as_value_or destination_ip{ U("destination_ip"), {} }; // string
const web::json::field_as_value_or source_port{ U("source_port"), {} }; // string or integer
const web::json::field_as_bool_or rtp_enabled{ U("rtp_enabled"), false };
const web::json::field_as_bool_or fec_enabled{ U("fec_enabled"), false };
const web::json::field_as_value_or fec_destination_ip{ U("fec_destination_ip"), {} }; // string
const web::json::field_as_string fec_type{ U("fec_type") };
const web::json::field_as_value_or fec_mode{ U("fec_mode"), {} }; // string
const web::json::field_as_integer fec_block_width{ U("fec_block_width") };
const web::json::field_as_integer fec_block_height{ U("fec_block_height") };
const web::json::field_as_value_or fec1D_destination_port{ U("fec1D_destination_port"), {} }; // string or integer
const web::json::field_as_value_or fec2D_destination_port{ U("fec2D_destination_port"), {} }; // string or integer
const web::json::field_as_value_or fec1D_source_port{ U("fec1D_source_port"), {} }; // string or integer
const web::json::field_as_value_or fec2D_source_port{ U("fec2D_source_port"), {} }; // string or integer
const web::json::field_as_bool_or rtcp_enabled{ U("rtcp_enabled"), false };
const web::json::field_as_value_or rtcp_destination_ip{ U("rtcp_destination_ip"), {} }; // string
const web::json::field_as_value_or rtcp_destination_port{ U("rtcp_destination_port"), {} }; // string or integer
const web::json::field_as_value_or rtcp_source_port{ U("rtcp_source_port"), {} }; // string or integer
const web::json::field_as_value_or fec_mode{ U("fec_mode"), {} }; // string
// for urn:x-nmos:transport:websocket
const web::json::field_as_value_or connection_uri{ U("connection_uri"), {} }; // string or null
const web::json::field_as_value_or connection_authorization{ U("connection_authorization"), {} }; // string or bool
Expand Down
Loading
Loading