From e6db12c4c489bf1b9218bb986caed13edafdd02b Mon Sep 17 00:00:00 2001 From: Konstantin Ilichev Date: Sat, 15 Feb 2025 23:58:02 +0000 Subject: [PATCH] Add support for Blob payload type Signed-off-by: Konstantin Ilichev --- control-plane-agent/internal/model/sdk.go | 17 ++ media-proxy/src/mesh/conn.cc | 5 + protos/conn-config.proto | 5 + sdk/src/mesh_conn.cc | 243 ++++++++++++---------- sdk/src/mesh_sdk_api.cc | 4 + sdk/tests/mesh_json_sdk_test.cc | 80 +++++-- 6 files changed, 221 insertions(+), 133 deletions(-) diff --git a/control-plane-agent/internal/model/sdk.go b/control-plane-agent/internal/model/sdk.go index d1de5dde..78c39329 100644 --- a/control-plane-agent/internal/model/sdk.go +++ b/control-plane-agent/internal/model/sdk.go @@ -45,6 +45,9 @@ type SDKConfigAudio struct { PacketTimeStr string `json:"packetTime"` } +type SDKConfigBlob struct { +} + type SDKConnectionConfig struct { BufQueueCapacity uint32 `json:"bufQueueCapacity"` MaxPayloadSize uint32 `json:"maxPayloadSize"` @@ -60,6 +63,7 @@ type SDKConnectionConfig struct { Payload struct { Video *SDKConfigVideo `json:"video,omitempty"` Audio *SDKConfigAudio `json:"audio,omitempty"` + Blob *SDKConfigBlob `json:"blob,omitempty"` } `json:"payload"` } @@ -158,6 +162,8 @@ func (s *SDKConnectionConfig) AssignFromPb(cfg *sdk.ConnectionConfig) error { Format: payload.Audio.Format, PacketTime: payload.Audio.PacketTime, } + case *sdk.ConnectionConfig_Blob: + s.Payload.Blob = &SDKConfigBlob{} default: return errors.New("unknown sdk conn cfg payload type") } @@ -217,6 +223,10 @@ func (s *SDKConnectionConfig) AssignToPb(cfg *sdk.ConnectionConfig) { PacketTime: s.Payload.Audio.PacketTime, }, } + case s.Payload.Blob != nil: + cfg.Payload = &sdk.ConnectionConfig_Blob{ + Blob: &sdk.ConfigBlob{}, + } } } @@ -276,6 +286,13 @@ func (s *SDKConnectionConfig) CheckPayloadCompatibility(c *SDKConnectionConfig) s.Payload.Audio.Channels, s.Payload.Audio.SampleRate, s.Payload.Audio.Format, s.Payload.Audio.PacketTime, c.Payload.Audio.Channels, c.Payload.Audio.SampleRate, c.Payload.Audio.Format, c.Payload.Audio.PacketTime) } + case s.Payload.Blob != nil: + if c.Payload.Blob == nil { + return errors.New("no blob cfg") + } + if s.MaxPayloadSize != c.MaxPayloadSize { + return fmt.Errorf("incompatible blob: sz:%v vs. sz:%v", s.MaxPayloadSize, c.MaxPayloadSize) + } default: return errors.New("unknown payload type") } diff --git a/media-proxy/src/mesh/conn.cc b/media-proxy/src/mesh/conn.cc index 99f40a53..37242388 100644 --- a/media-proxy/src/mesh/conn.cc +++ b/media-proxy/src/mesh/conn.cc @@ -585,6 +585,8 @@ Result Config::assign_from_pb(const sdk::ConnectionConfig& config) payload.audio.sample_rate = audio.sample_rate(); payload.audio.format = audio.format(); payload.audio.packet_time = audio.packet_time(); + } else if (config.has_blob()) { + payload_type = PayloadType::PAYLOAD_TYPE_BLOB; } else { return Result::error_payload_config_invalid; } @@ -634,6 +636,9 @@ void Config::assign_to_pb(sdk::ConnectionConfig& config) const audio->set_format(payload.audio.format); audio->set_packet_time(payload.audio.packet_time); config.set_allocated_audio(audio); + } else if (payload_type == PayloadType::PAYLOAD_TYPE_BLOB) { + auto blob = new sdk::ConfigBlob(); + config.set_allocated_blob(blob); } } diff --git a/protos/conn-config.proto b/protos/conn-config.proto index 2d33f8ce..8d13911b 100644 --- a/protos/conn-config.proto +++ b/protos/conn-config.proto @@ -80,6 +80,10 @@ message ConfigAudio { AudioPacketTime packet_time = 4; } +message ConfigBlob { + // To configure the blob size, max_payload_size must be populated with a non-zero value. +} + message ConnectionConfig { ConnectionKind kind = 1; uint32 buf_queue_capacity = 2; @@ -94,5 +98,6 @@ message ConnectionConfig { oneof payload { ConfigVideo video = 9; ConfigAudio audio = 10; + ConfigBlob blob = 11; } } diff --git a/sdk/src/mesh_conn.cc b/sdk/src/mesh_conn.cc index f0fc00fa..8eb45bfe 100644 --- a/sdk/src/mesh_conn.cc +++ b/sdk/src/mesh_conn.cc @@ -104,138 +104,148 @@ int ConnectionJsonConfig::parse_json(const char *str) if (!j.contains("payload")) { payload_type = MESH_PAYLOAD_TYPE_BLOB; - return 0; - } - - auto jpayload = j["payload"]; - - if (jpayload.contains("video")) - payload_type = MESH_PAYLOAD_TYPE_VIDEO; + } else { + auto jpayload = j["payload"]; - if (jpayload.contains("audio")) { - if (payload_type != MESH_PAYLOAD_TYPE_UNINITIALIZED) { - log::error("payload.audio config err: multiple payload types"); - return -MESH_ERR_CONN_CONFIG_INVAL; - } - payload_type = MESH_PAYLOAD_TYPE_AUDIO; - } + if (jpayload.contains("video")) + payload_type = MESH_PAYLOAD_TYPE_VIDEO; - if (jpayload.contains("blob")) { - if (payload_type != MESH_PAYLOAD_TYPE_UNINITIALIZED) { - log::error("payload.blob config err: multiple payload types"); - return -MESH_ERR_CONN_CONFIG_INVAL; + if (jpayload.contains("audio")) { + if (payload_type != MESH_PAYLOAD_TYPE_UNINITIALIZED) { + log::error("payload.audio config err: multiple payload types"); + return -MESH_ERR_CONN_CONFIG_INVAL; + } + payload_type = MESH_PAYLOAD_TYPE_AUDIO; } - payload_type = MESH_PAYLOAD_TYPE_BLOB; - } - if (payload_type == MESH_PAYLOAD_TYPE_UNINITIALIZED) { - log::error("payload config type not specified"); - return -MESH_ERR_CONN_CONFIG_INVAL; - } - - if (payload_type == MESH_PAYLOAD_TYPE_VIDEO) { - auto video = jpayload["video"]; - payload.video.width = video.value("width", 640); - payload.video.height = video.value("height", 640); - payload.video.fps = video.value("fps", 60.0); - - std::string str = video.value("pixelFormat", "yuv422p10le"); - if (!str.compare("yuv422p10le")) { - payload.video.pixel_format = MESH_VIDEO_PIXEL_FORMAT_YUV422PLANAR10LE; - } else if (!str.compare("v210")) { - payload.video.pixel_format = MESH_VIDEO_PIXEL_FORMAT_V210; - } else if (!str.compare("yuv422p10rfc4175")) { - payload.video.pixel_format = MESH_VIDEO_PIXEL_FORMAT_YUV422RFC4175BE10; - } else { - log::error("video: wrong pixel format: %s", str.c_str()); - return -MESH_ERR_CONN_CONFIG_INVAL; - } - } else if (payload_type == MESH_PAYLOAD_TYPE_AUDIO) { - auto audio = jpayload["audio"]; - payload.audio.channels = audio.value("channels", 2); - - std::string str = audio.value("format", "pcm_s24be"); - if (!str.compare("pcm_s24be")) { - payload.audio.format = MESH_AUDIO_FORMAT_PCM_S24BE; - } else if (!str.compare("pcm_s16be")) { - payload.audio.format = MESH_AUDIO_FORMAT_PCM_S16BE; - } else if (!str.compare("pcm_s8")) { - payload.audio.format = MESH_AUDIO_FORMAT_PCM_S8; - } else { - log::error("audio: wrong format: %s", str.c_str()); - return -MESH_ERR_CONN_CONFIG_INVAL; + if (jpayload.contains("blob")) { + if (payload_type != MESH_PAYLOAD_TYPE_UNINITIALIZED) { + log::error("payload.blob config err: multiple payload types"); + return -MESH_ERR_CONN_CONFIG_INVAL; + } + payload_type = MESH_PAYLOAD_TYPE_BLOB; } - int sample_rate = audio.value("sampleRate", 48000); - switch (sample_rate) { - case 44100: - payload.audio.sample_rate = MESH_AUDIO_SAMPLE_RATE_44100; - break; - case 48000: - payload.audio.sample_rate = MESH_AUDIO_SAMPLE_RATE_48000; - break; - case 96000: - payload.audio.sample_rate = MESH_AUDIO_SAMPLE_RATE_96000; - break; - default: - log::error("audio: wrong sample rate: %d", sample_rate); + if (payload_type == MESH_PAYLOAD_TYPE_UNINITIALIZED) { + log::error("payload config type not specified"); return -MESH_ERR_CONN_CONFIG_INVAL; } - str = audio.value("packetTime", "1ms"); - if (!str.compare("1ms")) { - } else if (!str.compare("1ms")) { - payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_1MS; - } else if (!str.compare("125us")) { - payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_125US; - } else if (!str.compare("250us")) { - payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_250US; - } else if (!str.compare("333us")) { - payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_333US; - } else if (!str.compare("4ms")) { - payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_4MS; - } else if (!str.compare("80us")) { - payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_80US; - } else if (!str.compare("1.09ms")) { - payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_1_09MS; - } else if (!str.compare("0.14ms")) { - payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_0_14MS; - } else if (!str.compare("0.09ms")) { - payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_1_09MS; - } else { - log::error("audio: wrong packet time: %s", str.c_str()); - return -MESH_ERR_CONN_CONFIG_INVAL; - } + if (payload_type == MESH_PAYLOAD_TYPE_VIDEO) { + auto video = jpayload["video"]; + payload.video.width = video.value("width", 640); + payload.video.height = video.value("height", 640); + payload.video.fps = video.value("fps", 60.0); + + std::string str = video.value("pixelFormat", "yuv422p10le"); + if (!str.compare("yuv422p10le")) { + payload.video.pixel_format = MESH_VIDEO_PIXEL_FORMAT_YUV422PLANAR10LE; + } else if (!str.compare("v210")) { + payload.video.pixel_format = MESH_VIDEO_PIXEL_FORMAT_V210; + } else if (!str.compare("yuv422p10rfc4175")) { + payload.video.pixel_format = MESH_VIDEO_PIXEL_FORMAT_YUV422RFC4175BE10; + } else { + log::error("video: wrong pixel format: %s", str.c_str()); + return -MESH_ERR_CONN_CONFIG_INVAL; + } + } else if (payload_type == MESH_PAYLOAD_TYPE_AUDIO) { + auto audio = jpayload["audio"]; + payload.audio.channels = audio.value("channels", 2); + + std::string str = audio.value("format", "pcm_s24be"); + if (!str.compare("pcm_s24be")) { + payload.audio.format = MESH_AUDIO_FORMAT_PCM_S24BE; + } else if (!str.compare("pcm_s16be")) { + payload.audio.format = MESH_AUDIO_FORMAT_PCM_S16BE; + } else if (!str.compare("pcm_s8")) { + payload.audio.format = MESH_AUDIO_FORMAT_PCM_S8; + } else { + log::error("audio: wrong format: %s", str.c_str()); + return -MESH_ERR_CONN_CONFIG_INVAL; + } - bool compatible = false; - switch (payload.audio.sample_rate) { - case MESH_AUDIO_SAMPLE_RATE_48000: - case MESH_AUDIO_SAMPLE_RATE_96000: - switch (payload.audio.packet_time) { - case MESH_AUDIO_PACKET_TIME_1MS: - case MESH_AUDIO_PACKET_TIME_125US: - case MESH_AUDIO_PACKET_TIME_250US: - case MESH_AUDIO_PACKET_TIME_333US: - case MESH_AUDIO_PACKET_TIME_4MS: - case MESH_AUDIO_PACKET_TIME_80US: - compatible = true; + int sample_rate = audio.value("sampleRate", 48000); + switch (sample_rate) { + case 44100: + payload.audio.sample_rate = MESH_AUDIO_SAMPLE_RATE_44100; + break; + case 48000: + payload.audio.sample_rate = MESH_AUDIO_SAMPLE_RATE_48000; + break; + case 96000: + payload.audio.sample_rate = MESH_AUDIO_SAMPLE_RATE_96000; break; + default: + log::error("audio: wrong sample rate: %d", sample_rate); + return -MESH_ERR_CONN_CONFIG_INVAL; } - break; - case MESH_AUDIO_SAMPLE_RATE_44100: - switch (payload.audio.packet_time) { - case MESH_AUDIO_PACKET_TIME_1_09MS: - case MESH_AUDIO_PACKET_TIME_0_14MS: - case MESH_AUDIO_PACKET_TIME_0_09MS: - compatible = true; + + str = audio.value("packetTime", "1ms"); + if (!str.compare("1ms")) { + } else if (!str.compare("1ms")) { + payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_1MS; + } else if (!str.compare("125us")) { + payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_125US; + } else if (!str.compare("250us")) { + payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_250US; + } else if (!str.compare("333us")) { + payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_333US; + } else if (!str.compare("4ms")) { + payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_4MS; + } else if (!str.compare("80us")) { + payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_80US; + } else if (!str.compare("1.09ms")) { + payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_1_09MS; + } else if (!str.compare("0.14ms")) { + payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_0_14MS; + } else if (!str.compare("0.09ms")) { + payload.audio.packet_time = MESH_AUDIO_PACKET_TIME_1_09MS; + } else { + log::error("audio: wrong packet time: %s", str.c_str()); + return -MESH_ERR_CONN_CONFIG_INVAL; + } + + bool compatible = false; + switch (payload.audio.sample_rate) { + case MESH_AUDIO_SAMPLE_RATE_48000: + case MESH_AUDIO_SAMPLE_RATE_96000: + switch (payload.audio.packet_time) { + case MESH_AUDIO_PACKET_TIME_1MS: + case MESH_AUDIO_PACKET_TIME_125US: + case MESH_AUDIO_PACKET_TIME_250US: + case MESH_AUDIO_PACKET_TIME_333US: + case MESH_AUDIO_PACKET_TIME_4MS: + case MESH_AUDIO_PACKET_TIME_80US: + compatible = true; + break; + } + break; + case MESH_AUDIO_SAMPLE_RATE_44100: + switch (payload.audio.packet_time) { + case MESH_AUDIO_PACKET_TIME_1_09MS: + case MESH_AUDIO_PACKET_TIME_0_14MS: + case MESH_AUDIO_PACKET_TIME_0_09MS: + compatible = true; + break; + } break; } - break; + if (!compatible) { + log::error("audio: sample rate incompatible with packet time"); + return -MESH_ERR_CONN_CONFIG_INCOMPAT; + } } - if (!compatible) { - log::error("audio: sample rate incompatible with packet time"); + } + + if (payload_type == MESH_PAYLOAD_TYPE_BLOB) { + if (conn_type != MESH_CONN_TYPE_GROUP) { + log::error("blob: conn type must be multipoint group"); return -MESH_ERR_CONN_CONFIG_INCOMPAT; } + if (!max_payload_size) { + log::error("blob: non-zero max payload size must be specified"); + return -MESH_ERR_CONN_CONFIG_INVAL; + } } return 0; @@ -381,6 +391,9 @@ int ConnectionJsonConfig::calc_payload_size() return calc_video_buf_size(); case MESH_PAYLOAD_TYPE_AUDIO: return calc_audio_buf_size(); + case MESH_PAYLOAD_TYPE_BLOB: + calculated_payload_size = max_payload_size; + return 0; } return -MESH_ERR_CONN_CONFIG_INVAL; diff --git a/sdk/src/mesh_sdk_api.cc b/sdk/src/mesh_sdk_api.cc index c7d7504b..a3bf5951 100644 --- a/sdk/src/mesh_sdk_api.cc +++ b/sdk/src/mesh_sdk_api.cc @@ -29,6 +29,7 @@ using sdk::ConfigST2110; using sdk::ConfigRDMA; using sdk::ConfigVideo; using sdk::ConfigAudio; +using sdk::ConfigBlob; using sdk::ST2110Transport; using sdk::VideoPixelFormat; using sdk::AudioSampleRate; @@ -148,6 +149,9 @@ class SDKAPIClient { audio->set_format((AudioFormat)cfg.payload.audio.format); audio->set_packet_time((AudioPacketTime)cfg.payload.audio.packet_time); config->set_allocated_audio(audio); + } else if (cfg.payload_type == MESH_PAYLOAD_TYPE_BLOB) { + auto blob = new ConfigBlob(); + config->set_allocated_blob(blob); } CreateConnectionResponse resp; diff --git a/sdk/tests/mesh_json_sdk_test.cc b/sdk/tests/mesh_json_sdk_test.cc index ec3d2add..628b2445 100644 --- a/sdk/tests/mesh_json_sdk_test.cc +++ b/sdk/tests/mesh_json_sdk_test.cc @@ -55,6 +55,9 @@ TEST(mesh_json_sdk, parse_conn_cfg_st2110) { "payloadType": 110, "transportPixelFormat": "yuv422p10rfc4175" } + }, + "payload": { + "video": {} } })"; @@ -69,27 +72,68 @@ TEST(mesh_json_sdk, parse_conn_cfg_st2110) { EXPECT_EQ(config.conn.st2110.pacing, "narrow"); EXPECT_EQ(config.conn.st2110.payload_type, 110); EXPECT_EQ(config.conn.st2110.transportPixelFormat, "yuv422p10rfc4175"); - EXPECT_EQ(config.payload_type, MESH_PAYLOAD_TYPE_BLOB); + EXPECT_EQ(config.payload_type, MESH_PAYLOAD_TYPE_VIDEO); } -TEST(mesh_json_sdk, parse_conn_cfg_rdma) { - const char *str = R"({ - "connection": { - "rdma": { - "connectionMode": "UC", - "maxLatencyNanoseconds": 10000 - } - } - })"; - - ConnectionJsonConfig config; - int err = config.parse_json(str); +// Temporarily commented out until there is a decision on RDMA config in JSON +// ---- +// TEST(mesh_json_sdk, parse_conn_cfg_rdma) { +// const char *str = R"({ +// "connection": { +// "rdma": { +// "connectionMode": "UC", +// "maxLatencyNanoseconds": 10000 +// } +// } +// })"; + +// ConnectionJsonConfig config; +// int err = config.parse_json(str); + +// ASSERT_EQ(err, 0); +// EXPECT_EQ(config.conn_type, MESH_CONN_TYPE_RDMA); +// EXPECT_EQ(config.conn.rdma.connection_mode, "UC"); +// EXPECT_EQ(config.conn.rdma.max_latency_ns, 10000); +// EXPECT_EQ(config.payload_type, MESH_PAYLOAD_TYPE_BLOB); +// } + +TEST(mesh_json_sdk, parse_conn_cfg_blob) { + const char *str = R"({ + "maxPayloadSize": 921600, + "connection": { + "multipointGroup": {} + }, + "payload": { + "blob": {} + } + })"; + + ConnectionJsonConfig config; + int err = config.parse_json(str); + + ASSERT_EQ(err, 0); + EXPECT_EQ(config.payload_type, MESH_PAYLOAD_TYPE_BLOB); + EXPECT_EQ(config.max_payload_size, 921600); +} - ASSERT_EQ(err, 0); - EXPECT_EQ(config.conn_type, MESH_CONN_TYPE_RDMA); - EXPECT_EQ(config.conn.rdma.connection_mode, "UC"); - EXPECT_EQ(config.conn.rdma.max_latency_ns, 10000); - EXPECT_EQ(config.payload_type, MESH_PAYLOAD_TYPE_BLOB); +TEST(mesh_json_sdk, parse_conn_cfg_blob_calc) { + const char *str = R"({ + "maxPayloadSize": 921600, + "connection": { + "multipointGroup": {} + }, + "payload": { + "blob": {} + } + })"; + + ConnectionJsonConfig config; + config.parse_json(str); + int err = config.calc_payload_size(); + + ASSERT_EQ(err, 0); + EXPECT_EQ(config.payload_type, MESH_PAYLOAD_TYPE_BLOB); + EXPECT_EQ(config.calculated_payload_size, 921600); } TEST(mesh_json_sdk, parse_conn_cfg_video) {