fabrics plan and easy fixes
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
# MXL Fabrics ingress plan
|
||||
|
||||
## Goal
|
||||
|
||||
Receive remote MXL audio and video through `go-mxl/fabrics`, place the received data into local MXL storage, and feed it into the existing player without changing playback, retry, session, synchronization, playlist, renderer, or audio-output semantics.
|
||||
|
||||
Start with the SHM provider. TCP, verbs, and EFA follow after the lifecycle and media paths are stable.
|
||||
|
||||
## Correct architecture
|
||||
|
||||
`go-mxl/fabrics` is not a second reader backend. A Fabrics target receives remote transfers into memory owned by a local `mxl.Writer`:
|
||||
|
||||
```text
|
||||
remote fabrics.Initiator
|
||||
|
|
||||
| remote transfer
|
||||
v
|
||||
fabrics.Target
|
||||
|
|
||||
| writes into a local mxl.Writer ring
|
||||
v
|
||||
local MXL flow
|
||||
|
|
||||
v
|
||||
VideoFrame / AudioSamples -> playback workers -> output
|
||||
```
|
||||
|
||||
Consequences:
|
||||
|
||||
- the local MXL media path remains the reference implementation;
|
||||
- Fabrics is an ingress/transport concern, not a playback backend;
|
||||
- playback and playlist code must not know about providers or endpoints;
|
||||
- each remotely transferred flow requires its own target;
|
||||
- target completions must be matched to the exact local grain/sample range;
|
||||
- do not add a blind polling loop that could return stale or overwritten media.
|
||||
|
||||
## Confirmed API facts
|
||||
|
||||
The project pins `github.com/qvest-digital/go-mxl v1.1.0-rc.1`. It includes `github.com/qvest-digital/go-mxl/fabrics` and providers `shm`, `tcp`, `verbs`, `efa`, and `any`.
|
||||
|
||||
The receive-side flow is:
|
||||
|
||||
1. create a local `mxl.Instance`;
|
||||
2. create an `mxl.Writer` from the flow definition;
|
||||
3. create a `fabrics.Instance` from the local MXL instance;
|
||||
4. create a `fabrics.Target`;
|
||||
5. call `Target.Setup` with provider, node/service, writer, and options;
|
||||
6. publish the returned `TargetInfo` to the remote initiator;
|
||||
7. consume completions with `ReadGrain` or `ReadSamples`.
|
||||
|
||||
`TargetInfo` is control-plane data. Initially serialize it to a file for the known sender; automatic discovery is out of scope.
|
||||
|
||||
`fabrics.ErrNotReady` means no completion is ready before the timeout. `fabrics.ErrInterrupted` can be caused by Go runtime signals and means retry the read operation. Neither is a feed failure by itself.
|
||||
|
||||
## Current native-library state
|
||||
|
||||
The installed pkg-config metadata reports `libmxl 1.2.0.0` and `libmxl-fabrics 1.2.0.0`. The pinned Go module records native MXL `v1.1.0-rc1` as its corresponding version. Resolving `libmxl-fabrics` currently fails because pkg-config cannot find `libfabric`.
|
||||
|
||||
This does not prove 1.2 is incompatible. Compare the stack with the user's known-working C++ sender/receiver and choose one tested version set. Do not conceal ABI/API mismatches with casts or copied declarations.
|
||||
|
||||
## Configuration boundary
|
||||
|
||||
Fabrics code should live in `internal/adapter/mxlfabrics`. A provisional configuration is:
|
||||
|
||||
```go
|
||||
type IngressConfig struct {
|
||||
Provider fabrics.Provider
|
||||
Node string
|
||||
Service string
|
||||
Options json.RawMessage
|
||||
TargetInfoPath string
|
||||
Flow mxl.FlowDefinition
|
||||
}
|
||||
```
|
||||
|
||||
Use the exact flow-definition type exposed by the selected library version. Video and audio have independent configurations and targets. They may use different remote endpoints/providers while landing in the same local MXL domain.
|
||||
|
||||
Do not add `--backend local|fabrics`. The useful distinction is whether a feed is already local or needs Fabrics ingress. Choose final per-feed CLI names after the configuration spike.
|
||||
|
||||
## Implementation stages
|
||||
|
||||
### Stage 0 — Align and prove the native stack
|
||||
|
||||
- Record exact versions/commits of `libfabric`, `libmxl`, `libmxl-fabrics`, and `go-mxl` used by the working C++ pair.
|
||||
- Decide whether to retain Go/native 1.1 RC or move the complete set together.
|
||||
- Make all pkg-config and dynamic-linker checks pass.
|
||||
- Run the known C++ pair, then the matching upstream Go SHM target/initiator examples.
|
||||
- Enumerate interfaces/providers through the Go API.
|
||||
- Preserve the current player test baseline.
|
||||
|
||||
```sh
|
||||
pkg-config --modversion libfabric libmxl libmxl-fabrics
|
||||
pkg-config --cflags --libs libfabric libmxl libmxl-fabrics
|
||||
ldd /usr/local/lib/libmxl-fabrics.so
|
||||
go test ./...
|
||||
```
|
||||
|
||||
Acceptance: one documented compatible version set; repeatable Go SHM transfer; clean cancellation/shutdown; no player production changes.
|
||||
|
||||
### Stage 1 — Minimal SHM ingress spike
|
||||
|
||||
- Create a local MXL instance and writer from a supplied flow definition.
|
||||
- Set up one SHM target and serialize its `TargetInfo` to an explicit file.
|
||||
- Receive video grains and audio sample ranges from the known sender in isolated experiments.
|
||||
- Verify completion indices against the corresponding local ring contents.
|
||||
- Document buffer lifetime, overwrite behavior, and sender-absent behavior.
|
||||
|
||||
Acceptance: video and audio transfers work independently; no busy loop; shutdown promptly releases resources.
|
||||
|
||||
### Stage 2 — Define the ingress lifecycle
|
||||
|
||||
Create a narrow adapter owned by the composition root. It must:
|
||||
|
||||
- validate before allocating native resources;
|
||||
- create the writer before target setup and publish info only after setup;
|
||||
- classify timeouts, interruptions, cancellation, and terminal errors;
|
||||
- remain context-cancellable although native reads use timeouts;
|
||||
- allow only one completion reader per target;
|
||||
- close every resource exactly once and unwind partial setup safely.
|
||||
|
||||
Confirm the precise close order against the chosen version. Expected order:
|
||||
|
||||
1. cancel and join the completion loop;
|
||||
2. close target;
|
||||
3. close returned `TargetInfo`;
|
||||
4. close the Fabrics instance after all targets;
|
||||
5. close local readers/writers while respecting the target's writer reference;
|
||||
6. close the local MXL instance last.
|
||||
|
||||
Acceptance: allocation-failure tests, prompt idle/active cancellation, race-safe repeated start/stop, and no resource leaks.
|
||||
|
||||
### Stage 3 — Video ingress
|
||||
|
||||
- Receive completion indices and obtain the exact completed local grain.
|
||||
- Map metadata/payload into `playback.VideoFrame`.
|
||||
- Preserve borrowed-buffer lifetime, or make one deliberate bounded copy if required for safety.
|
||||
- Reject unsupported formats explicitly.
|
||||
- Track received, delivered, overwritten, and malformed grains.
|
||||
|
||||
Never independently poll for the newest local frame after a completion; it may be a different index.
|
||||
|
||||
Acceptance: correct V210 playback; monotonic indices except documented restart; stable 25/50/59.94/high-rate playback; clean disappearance/restoration.
|
||||
|
||||
### Stage 4 — Audio ingress
|
||||
|
||||
- Use `ReadSamples` completion ranges and read exactly the reported head/count.
|
||||
- Map rate, channels, format, label, UUID, and index into the audio contract.
|
||||
- Preserve SDL backpressure and queue policy.
|
||||
- Track samples, discontinuities, overruns, and queue depth.
|
||||
|
||||
Acceptance: correct mono/stereo/multichannel and common rates; no corruption/drift; no duplicated/skipped ranges; no stale queued audio after stop/reconnect.
|
||||
|
||||
### Stage 5 — Independent and synchronized A/V
|
||||
|
||||
Independent A/V uses two independent targets/lifecycles; one failure must not stop the other.
|
||||
|
||||
For synchronized A/V:
|
||||
|
||||
- land both flows in a compatible local MXL domain;
|
||||
- retain native local-MXL synchronization where supported;
|
||||
- coordinate completion availability so sync never consumes data not yet received;
|
||||
- verify different endpoints/providers and fractional frame rates such as 59.94.
|
||||
|
||||
Fabrics transports media; it is not a reason to invent manual synchronization. If native synchronization cannot safely use received rings, write a separate sync design first.
|
||||
|
||||
Acceptance: failure isolation when independent; one retry lifecycle when synchronized; runtime sync toggle retains current semantics; long playback stays aligned.
|
||||
|
||||
### Stage 6 — Player integration
|
||||
|
||||
- Add per-feed local/Fabrics transport configuration.
|
||||
- Construct ingress outside `internal/playback` and connect it to existing workers/slots.
|
||||
- Preserve stop, resume, replace, remove, sync toggle, retry, and playlist behavior.
|
||||
- Keep playlist entries provider-neutral where possible.
|
||||
- Add provider, endpoint, ingress state, completion age, and counters to stats.
|
||||
|
||||
Acceptance: local behavior is unchanged; Fabrics supports video-only, audio-only, independent A/V, and sync A/V; bad config fails before native goroutines; feeds remain independently controllable.
|
||||
|
||||
### Stage 7 — Provider rollout
|
||||
|
||||
Enable and validate in order:
|
||||
|
||||
1. SHM;
|
||||
2. TCP;
|
||||
3. verbs;
|
||||
4. EFA if deployment requires it.
|
||||
|
||||
Provider selection should affect only Fabrics interface configuration and deployment prerequisites. Playback controllers must not branch on provider names.
|
||||
|
||||
### Stage 8 — Playlist and resilience validation
|
||||
|
||||
Test empty startup; audio/video only; independent and synchronized A/V; either sender disappearing/restoring; finite/infinite retry; stop/resume/remove/replace; sync toggling during playback/backoff; `wait`/`next` playlists; timed looping/manual navigation; 59.94/high-rate video; and repeated long-running startup/shutdown.
|
||||
|
||||
Record CPU, memory, received/displayed FPS, completion delta, dropped/overwritten media, audio queue, reconnect latency, and native resource counts.
|
||||
|
||||
## Test layers
|
||||
|
||||
1. Unit tests for configuration, error classification, and lifecycle transitions.
|
||||
2. Adapter tests with injected wrappers around native allocations and reads.
|
||||
3. Real SHM initiator/target integration tests.
|
||||
4. Player smoke tests for all playback combinations.
|
||||
5. Race and repeated lifecycle tests.
|
||||
6. Provider-specific TCP/verbs/EFA live tests.
|
||||
|
||||
Native/live tests must be explicit integration tests and skip with a useful reason when prerequisites are absent.
|
||||
|
||||
## Out of scope for the first pass
|
||||
|
||||
- player as Fabrics initiator/sender;
|
||||
- automatic endpoint or TargetInfo discovery;
|
||||
- changing provider on an active target;
|
||||
- manual A/V sync without a reviewed design;
|
||||
- new media formats bundled into transport work;
|
||||
- provider-specific logic in playback, playlist, renderer, or GUI;
|
||||
- unsafe workarounds for native version mismatches.
|
||||
|
||||
## First action tomorrow
|
||||
|
||||
1. Build/install the exact known-working native stack.
|
||||
2. Record every native version/commit and the C++ reference commands.
|
||||
3. Make all pkg-config checks pass.
|
||||
4. Run the C++ sender/receiver baseline.
|
||||
5. Run the matching upstream Go SHM target/initiator example.
|
||||
6. Capture its flow definition and `TargetInfo` exchange.
|
||||
7. Start Stage 1 only when transfer and clean shutdown are repeatable.
|
||||
Reference in New Issue
Block a user