Skip to content

Commit 64ef465

Browse files
authored
Add RDMA bridge optional parameters in SDK JSON config (#397)
* Add the `provider` string parameter, options are `tcp` or `verbs`, default `tcp`. * Add the `numEndpoints` integer parameter, range 1..8, default 1. * If one or both parameters are not equal, fail compatibility check. * Implement JSON parameter parsing. * Propagate parameters all the way down to Media Proxy and Agent. * Make both parameters appear in create_bridge() to allow passing them to configuration of RDMA brodge classes. * Update SDK documentation. * Add corresponding parameters `rdma_provider` and `rdma_num_endpoints` in FFmpeg Plugin. * Update FFmpeg Plugin documentation. Signed-off-by: Konstantin Ilichev <[email protected]>
1 parent fb0a205 commit 64ef465

File tree

16 files changed

+256
-7
lines changed

16 files changed

+256
-7
lines changed

control-plane-agent/internal/model/sdk.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ type SDKConfigRDMA struct {
3939
MaxLatencyNs uint32 `json:"maxLatencyNs"`
4040
}
4141

42+
type SDKConnectionOptionsRDMA struct {
43+
Provider string `json:"provider,omitempty"`
44+
NumEndpoints uint8 `json:"numEndpoints,omitempty"`
45+
}
46+
4247
type SDKConfigVideo struct {
4348
Width uint32 `json:"width"`
4449
Height uint32 `json:"height"`
@@ -74,6 +79,10 @@ type SDKConnectionConfig struct {
7479
RDMA *SDKConfigRDMA `json:"rdma,omitempty"`
7580
} `json:"conn"`
7681

82+
Options struct {
83+
RDMA SDKConnectionOptionsRDMA `json:"rdma"`
84+
} `json:"options"`
85+
7786
Payload struct {
7887
Video *SDKConfigVideo `json:"video,omitempty"`
7988
Audio *SDKConfigAudio `json:"audio,omitempty"`
@@ -178,6 +187,11 @@ func (s *SDKConnectionConfig) AssignFromPb(cfg *sdk.ConnectionConfig) error {
178187
return errors.New("unknown sdk conn cfg type")
179188
}
180189

190+
if cfg.Options != nil && cfg.Options.Rdma != nil {
191+
s.Options.RDMA.Provider = cfg.Options.Rdma.Provider
192+
s.Options.RDMA.NumEndpoints = uint8(cfg.Options.Rdma.NumEndpoints)
193+
}
194+
181195
switch payload := cfg.Payload.(type) {
182196
case *sdk.ConnectionConfig_Video:
183197
s.Payload.Video = &SDKConfigVideo{
@@ -251,6 +265,13 @@ func (s *SDKConnectionConfig) AssignToPb(cfg *sdk.ConnectionConfig) {
251265
}
252266
}
253267

268+
cfg.Options = &sdk.ConnectionOptions{
269+
Rdma: &sdk.ConnectionOptionsRDMA{
270+
Provider: s.Options.RDMA.Provider,
271+
NumEndpoints: uint32(s.Options.RDMA.NumEndpoints),
272+
},
273+
}
274+
254275
switch {
255276
case s.Payload.Video != nil:
256277
cfg.Payload = &sdk.ConnectionConfig_Video{
@@ -311,6 +332,13 @@ func (s *SDKConnectionConfig) CheckPayloadCompatibility(c *SDKConnectionConfig)
311332
}
312333
}
313334

335+
if s.Options.RDMA.Provider != c.Options.RDMA.Provider {
336+
return fmt.Errorf("incompatible rdma provider: %v vs. %v", s.Options.RDMA.Provider, c.Options.RDMA.Provider)
337+
}
338+
if s.Options.RDMA.NumEndpoints != c.Options.RDMA.NumEndpoints {
339+
return fmt.Errorf("incompatible rdma number of endpoints: %v vs. %v", s.Options.RDMA.NumEndpoints, c.Options.RDMA.NumEndpoints)
340+
}
341+
314342
switch {
315343
case s.Payload.Video != nil:
316344
if c.Payload.Video == nil {

docs/FFmpegPlugin.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ Refer to the [SDK API Definition](SDK_API_Definition.md) for the options of conf
9393
|----------|------------------------------------------------------------------------|---------------------|
9494
| `-urn` | Multipoint group Uniform Resource Name, or URN. Default "192.168.97.1" | `-urn 192.168.97.1` |
9595

96+
### Connection options – RDMA ingress/egress bridge related parameters
97+
98+
| Argument | Description | Example |
99+
|-----------------------|-------------------------------------------|-------------------------|
100+
| `-rdma_provider` | RDMA provider type. Default "tcp" | `-rdma_provider verbs` |
101+
| `-rdma_num_endpoints` | Number of RDMA endpoints, 1..8. Default 1 | `-rdma_num_endpoints 4` |
102+
96103
### Video payload parameters
97104

98105
| Argument | Description | Example |

docs/SDK_API_Definition.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ Creates a transmitter connection with the provided JSON configuration.
8282
"transportPixelFormat": "yuv422p10rfc4175"
8383
},
8484
},
85+
"options": {
86+
"rdma": {
87+
"provider": "tcp",
88+
"numEndpoints": 2,
89+
}
90+
},
8591
"payload": {
8692
"video": {
8793
"width": 1920,
@@ -120,6 +126,16 @@ to setup various connection and payload options. The examples correspond to the
120126
}
121127
```
122128

129+
### Configure connection options
130+
```json
131+
"options": {
132+
"rdma": {
133+
"provider": "tcp",
134+
"numEndpoints": 2,
135+
}
136+
},
137+
```
138+
123139
### Configure payload – Video
124140
```json
125141
"payload": {
@@ -181,6 +197,12 @@ The above `maxPayloadSize` is set explicitly to define the buffer size for the B
181197
* `"transportPixelFormat"` – Required only for the `"st2110-20"` transport type, default "yuv422p10rfc4175".
182198
1. `"multipointGroup"` – Multipoint Group connection.
183199
* `"urn"` – Uniform Resource Name (URN) of the multipoint group, e.g. "ipv4:224.0.0.1:9003".
200+
* `"options"` – Connection options
201+
* `"rdma"` – RDMA bridge related parameters
202+
* `"provider"` – Default "tcp".
203+
* `"tcp"`
204+
* `"verbs"`
205+
* `"numEndpoints"` – Integer number of RDMA endpoints between 1-8, default 1.
184206
* `"payload"` – Payload type, options 1-3 are the following:
185207
1. `"video"` – Video payload.
186208
* `"width"` – Integer frame width, e.g. 1920.

ffmpeg-plugin/mcm_audio_rx.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ typedef struct McmAudioDemuxerContext {
3535
int sample_rate;
3636
char* ptime;
3737

38+
char *rdma_provider;
39+
int rdma_num_endpoints;
40+
3841
MeshClient *mc;
3942
MeshConnection *conn;
4043
bool first_frame;
@@ -58,14 +61,16 @@ static int mcm_audio_read_header(AVFormatContext* avctx, enum AVCodecID codec_id
5861
n = snprintf(json_config, sizeof(json_config),
5962
mcm_json_config_multipoint_group_audio_format,
6063
s->buf_queue_cap, s->conn_delay,
61-
s->urn, s->channels, s->sample_rate,
64+
s->urn, s->rdma_provider, s->rdma_num_endpoints,
65+
s->channels, s->sample_rate,
6266
avcodec_get_name(codec_id), s->ptime);
6367

6468
} else if (!strcmp(s->conn_type, "st2110")) {
6569
n = snprintf(json_config, sizeof(json_config),
6670
mcm_json_config_st2110_audio_format,
6771
s->buf_queue_cap, s->conn_delay,
6872
s->ip_addr, s->port, s->mcast_sip_addr, s->payload_type,
73+
s->rdma_provider, s->rdma_num_endpoints,
6974
s->channels, s->sample_rate,
7075
avcodec_get_name(codec_id), s->ptime);
7176
} else {
@@ -219,6 +224,8 @@ static const AVOption mcm_audio_rx_options[] = {
219224
{ "channels", "number of audio channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, DEC },
220225
{ "sample_rate", "audio sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, DEC },
221226
{ "ptime", "audio packet time", OFFSET(ptime), AV_OPT_TYPE_STRING, {.str = "1ms"}, .flags = DEC },
227+
{ "rdma_provider", "optional: set RDMA provider type ('tcp' or 'verbs')", OFFSET(rdma_provider), AV_OPT_TYPE_STRING, {.str = "tcp"}, .flags = DEC },
228+
{ "rdma_num_endpoints", "optional: set number of RDMA endpoints, range 1..8", OFFSET(rdma_num_endpoints), AV_OPT_TYPE_INT, {.i64 = 1}, 1, 8, DEC },
222229
{ NULL },
223230
};
224231

ffmpeg-plugin/mcm_audio_tx.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ typedef struct McmAudioMuxerContext {
3131
int sample_rate;
3232
char* ptime;
3333

34+
char *rdma_provider;
35+
int rdma_num_endpoints;
36+
3437
MeshClient *mc;
3538
MeshConnection *conn;
3639
MeshBuffer *unsent_buf;
@@ -69,14 +72,16 @@ static int mcm_audio_write_header(AVFormatContext* avctx)
6972
n = snprintf(json_config, sizeof(json_config),
7073
mcm_json_config_multipoint_group_audio_format,
7174
s->buf_queue_cap, s->conn_delay,
72-
s->urn, s->channels, s->sample_rate,
75+
s->urn, s->rdma_provider, s->rdma_num_endpoints,
76+
s->channels, s->sample_rate,
7377
avcodec_get_name(codecpar->codec_id), s->ptime);
7478

7579
} else if (!strcmp(s->conn_type, "st2110")) {
7680
n = snprintf(json_config, sizeof(json_config),
7781
mcm_json_config_st2110_audio_format,
7882
s->buf_queue_cap, s->conn_delay,
7983
s->ip_addr, s->port, "", s->payload_type,
84+
s->rdma_provider, s->rdma_num_endpoints,
8085
s->channels, s->sample_rate,
8186
avcodec_get_name(codecpar->codec_id), s->ptime);
8287
} else {
@@ -213,6 +218,8 @@ static const AVOption mcm_audio_tx_options[] = {
213218
{ "channels", "number of audio channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, ENC },
214219
{ "sample_rate", "audio sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, ENC },
215220
{ "ptime", "audio packet time", OFFSET(ptime), AV_OPT_TYPE_STRING, {.str = "1ms"}, .flags = ENC },
221+
{ "rdma_provider", "optional: set RDMA provider type ('tcp' or 'verbs')", OFFSET(rdma_provider), AV_OPT_TYPE_STRING, {.str = "tcp"}, .flags = ENC },
222+
{ "rdma_num_endpoints", "optional: set number of RDMA endpoints, range 1..8", OFFSET(rdma_num_endpoints), AV_OPT_TYPE_INT, {.i64 = 1}, 1, 8, ENC },
216223
{ NULL },
217224
};
218225

ffmpeg-plugin/mcm_common.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ const char mcm_json_config_multipoint_group_video_format[] =
139139
"`urn`: `%s`"
140140
"}"
141141
"},"
142+
"`options`: {"
143+
"`rdma`: {"
144+
"`provider`: `%s`,"
145+
"`num_endpoints`: %d"
146+
"}"
147+
"},"
142148
"`payload`: {"
143149
"`video`: {"
144150
"`width`: %d,"
@@ -163,6 +169,12 @@ const char mcm_json_config_st2110_video_format[] =
163169
"`transportPixelFormat`: `%s`"
164170
"}"
165171
"},"
172+
"`options`: {"
173+
"`rdma`: {"
174+
"`provider`: `%s`,"
175+
"`num_endpoints`: %d"
176+
"}"
177+
"},"
166178
"`payload`: {"
167179
"`video`: {"
168180
"`width`: %d,"
@@ -182,6 +194,12 @@ const char mcm_json_config_multipoint_group_audio_format[] =
182194
"`urn`: `%s`"
183195
"}"
184196
"},"
197+
"`options`: {"
198+
"`rdma`: {"
199+
"`provider`: `%s`,"
200+
"`num_endpoints`: %d"
201+
"}"
202+
"},"
185203
"`payload`: {"
186204
"`audio`: {"
187205
"`channels`: %d,"
@@ -205,6 +223,12 @@ const char mcm_json_config_st2110_audio_format[] =
205223
"`payloadType`: %d"
206224
"}"
207225
"},"
226+
"`options`: {"
227+
"`rdma`: {"
228+
"`provider`: `%s`,"
229+
"`num_endpoints`: %d"
230+
"}"
231+
"},"
208232
"`payload`: {"
209233
"`audio`: {"
210234
"`channels`: %d,"

ffmpeg-plugin/mcm_video_rx.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ typedef struct McmVideoDemuxerContext {
3838
enum AVPixelFormat pixel_format;
3939
AVRational frame_rate;
4040

41+
char *rdma_provider;
42+
int rdma_num_endpoints;
43+
4144
MeshClient *mc;
4245
MeshConnection *conn;
4346
bool first_frame;
@@ -61,7 +64,8 @@ static int mcm_video_read_header(AVFormatContext* avctx)
6164
n = snprintf(json_config, sizeof(json_config),
6265
mcm_json_config_multipoint_group_video_format,
6366
s->buf_queue_cap, s->conn_delay,
64-
s->urn, s->width, s->height, av_q2d(s->frame_rate),
67+
s->urn, s->rdma_provider, s->rdma_num_endpoints,
68+
s->width, s->height, av_q2d(s->frame_rate),
6569
av_get_pix_fmt_name(s->pixel_format));
6670
} else if (!strcmp(s->conn_type, "st2110")) {
6771
n = snprintf(json_config, sizeof(json_config),
@@ -70,6 +74,7 @@ static int mcm_video_read_header(AVFormatContext* avctx)
7074
s->ip_addr, s->port, s->mcast_sip_addr,
7175
s->transport, s->payload_type,
7276
s->transport_pixel_format,
77+
s->rdma_provider, s->rdma_num_endpoints,
7378
s->width, s->height, av_q2d(s->frame_rate),
7479
av_get_pix_fmt_name(s->pixel_format));
7580
} else {
@@ -213,6 +218,8 @@ static const AVOption mcm_video_rx_options[] = {
213218
{ "video_size", "set video frame size given a string such as 640x480 or hd720", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = "1920x1080"}, 0, 0, DEC },
214219
{ "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_YUV422P10LE}, AV_PIX_FMT_NONE, INT_MAX, DEC },
215220
{ "frame_rate", "set video frame rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC },
221+
{ "rdma_provider", "optional: set RDMA provider type ('tcp' or 'verbs')", OFFSET(rdma_provider), AV_OPT_TYPE_STRING, {.str = "tcp"}, .flags = DEC },
222+
{ "rdma_num_endpoints", "optional: set number of RDMA endpoints, range 1..8", OFFSET(rdma_num_endpoints), AV_OPT_TYPE_INT, {.i64 = 1}, 1, 8, DEC },
216223
{ NULL },
217224
};
218225

ffmpeg-plugin/mcm_video_tx.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ typedef struct McmVideoMuxerContext {
3333
enum AVPixelFormat pixel_format;
3434
AVRational frame_rate;
3535

36+
char *rdma_provider;
37+
int rdma_num_endpoints;
38+
3639
MeshClient *mc;
3740
MeshConnection *conn;
3841
} McmVideoMuxerContext;
@@ -54,7 +57,8 @@ static int mcm_video_write_header(AVFormatContext* avctx)
5457
n = snprintf(json_config, sizeof(json_config),
5558
mcm_json_config_multipoint_group_video_format,
5659
s->buf_queue_cap, s->conn_delay,
57-
s->urn, s->width, s->height, av_q2d(s->frame_rate),
60+
s->urn, s->rdma_provider, s->rdma_num_endpoints,
61+
s->width, s->height, av_q2d(s->frame_rate),
5862
av_get_pix_fmt_name(s->pixel_format));
5963
} else if (!strcmp(s->conn_type, "st2110")) {
6064
n = snprintf(json_config, sizeof(json_config),
@@ -63,6 +67,7 @@ static int mcm_video_write_header(AVFormatContext* avctx)
6367
s->ip_addr, s->port, "",
6468
s->transport, s->payload_type,
6569
s->transport_pixel_format,
70+
s->rdma_provider, s->rdma_num_endpoints,
6671
s->width, s->height, av_q2d(s->frame_rate),
6772
av_get_pix_fmt_name(s->pixel_format));
6873
} else {
@@ -162,6 +167,8 @@ static const AVOption mcm_video_tx_options[] = {
162167
{ "video_size", "set video frame size given a string such as 640x480 or hd720", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = "1920x1080"}, 0, 0, ENC },
163168
{ "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_YUV422P10LE}, AV_PIX_FMT_NONE, INT_MAX, ENC },
164169
{ "frame_rate", "set video frame rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, ENC },
170+
{ "rdma_provider", "optional: set RDMA provider type ('tcp' or 'verbs')", OFFSET(rdma_provider), AV_OPT_TYPE_STRING, {.str = "tcp"}, .flags = ENC },
171+
{ "rdma_num_endpoints", "optional: set number of RDMA endpoints, range 1..8", OFFSET(rdma_num_endpoints), AV_OPT_TYPE_INT, {.i64 = 1}, 1, 8, ENC },
165172
{ NULL },
166173
};
167174

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# SDK Bridge-related Parameter Propagation — Developer's Guide
2+
3+
SDK allows passing some parameters to be applied when Egress or Ingress Bridge is created in Media Proxy.
4+
5+
When adding or modifying any of the RDMA or SMPTE ST 2110 SDK parameters, many parts of code should be adjusted accordingly. The affected software components are SDK, Media Proxy, and Agent.
6+
7+
The following diagram shows the propagation flow of SDK parameters from the JSON configuration to the bridge's `configure()` method. RDMA classes are taken as an example.
8+
9+
> Note: Each function AND each data structure mentioned in the diagram should be revised and adjusted appropriately.
10+
11+
```mermaid
12+
flowchart
13+
a1(["mesh_create_tx_connection()
14+
mesh_create_rx_connection()"])
15+
16+
subgraph sdk [SDK]
17+
direction TB
18+
a2("parse_from_json()")
19+
a3("CreateConnectionJson()")
20+
end
21+
22+
subgraph proxy [Media Proxy]
23+
direction TB
24+
a4("connection::Config.assign_from_pb()")
25+
a5("connection::Config.assign_to_pb()")
26+
a8("StartCommandQueue()")
27+
a9("create_bridge()")
28+
a10("RdmaTx::configure()
29+
RdmaRx::configure()")
30+
end
31+
32+
subgraph agent [Agent]
33+
direction TB
34+
a6("SDKConnectionConfig.AssignFromPb()")
35+
a6-1("CheckPayloadCompatibility()")
36+
a7("SDKConnectionConfig.AssignToPb()")
37+
end
38+
39+
a1 -- JSON config --> a2 -- mesh::ConnectionConfig --> a3
40+
a3 -- Protobuf sdk::ConnectionConfig --> a4 -- connection::Config --> a5
41+
a5 -- Protobuf sdk.ConnectionConfig --> a6 -- SDKConnectionConfig --> a6-1
42+
a6-1 -- SDKConnectionConfig --> a7
43+
a7 -- Protobuf sdk.ConnectionConfig --> a8 -- BridgeConfig --> a9
44+
a9 -- Rdma class config struct --> a10
45+
```
46+
47+
## Checklist: What to adjust to enable passing SDK parameters to the recipient class configuration?
48+
49+
1. Adjust the SDK code
50+
* Structure `mesh::ConnectionConfig`.
51+
* Method `parse_from_json()`
52+
* Proto file `conn-config.proto` – Add/Modify/Remove fields.
53+
* Method `CreateConnectionJson()`.
54+
1. Adjust the Media Proxy code
55+
* Structure `connection::Config`.
56+
* Method `connection::Config.assign_from_pb()`.
57+
* Method `connection::Config.assign_to_pb()`.
58+
1. Adjust the Agent code
59+
* Structure `SDKConnectionConfig`.
60+
* Function `SDKConnectionConfig.AssignFromPb()`.
61+
* Function `CheckPayloadCompatibility()`.
62+
* Function `SDKConnectionConfig.AssignToPb()`.
63+
1. Adjust the Media Proxy code
64+
* Structure `BridgeConfig`.
65+
* Method `StartCommandQueue()`.
66+
* Recipient class config struct, e.g. RDMA.
67+
* Method `create_bridge()`.
68+
1. Update documentation.

0 commit comments

Comments
 (0)