├── rust ├── flake.lock ├── Cargo.lock.license ├── mxl-sys │ ├── .gitignore │ ├── wrapper-with-version-h.h │ ├── wrapper-without-version-h.h │ ├── tests │ │ └── simple_test.rs │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── .gitattributes ├── .gitignore ├── mxl │ ├── src │ │ ├── grain.rs │ │ ├── samples.rs │ │ ├── api.rs │ │ ├── lib.rs │ │ ├── config.rs │ │ ├── grain │ │ │ ├── data.rs │ │ │ └── writer.rs │ │ ├── error.rs │ │ └── samples │ │ │ ├── writer.rs │ │ │ └── data.rs │ ├── examples │ │ └── common │ │ │ └── mod.rs │ ├── Cargo.toml │ └── build.rs ├── .config │ └── nextest.toml ├── deny.toml ├── README.md ├── Cargo.toml └── flake.nix ├── GOVERNANCE ├── .gitkeep ├── CHARTER.pdf ├── CHARTER.pdf.license ├── MXL-Requirement-Feature-Workflow-2025-10-09.png ├── MXL-Requirement-Feature-Workflow-2025-10-09.png.license └── DoD.md ├── docs ├── Media eXchange Layer.png ├── fabrics │ └── img │ │ ├── mxl-fabrics-rma.png │ │ ├── mxl-fabrics-overview.png │ │ ├── mxl-fabrics-bouncebuffer.png │ │ ├── mxl-fabrics-grain-layout.png │ │ ├── mxl-fabrics-cont-flow-rma.png │ │ ├── mxl-fabrics-rma-with-alpha.png │ │ ├── mxl-fabrics-cont-flow-layout.png │ │ ├── mxl-fabrics-rma.png.license │ │ ├── mxl-fabrics-overview.png.license │ │ ├── mxl-fabrics-bouncebuffer.png.license │ │ ├── mxl-fabrics-cont-flow-rma.png.license │ │ ├── mxl-fabrics-grain-layout.png.license │ │ ├── mxl-fabrics-rma-with-alpha.png.license │ │ └── mxl-fabrics-cont-flow-layout.png.license ├── logo │ ├── png │ │ ├── mxl-on-blue-square-128px.png │ │ └── mxl-on-blue-square-128px.png.license │ ├── mxl-on-blue-square.svg.license │ ├── mxl-on-blue-rectangular.svg.license │ ├── mxl-on-white-square.svg.license │ ├── mxl-on-white-rectangular.svg.license │ └── mxl-on-blue-rectangular-supporter.svg.license ├── assets │ ├── continuous-flow-memory-layout.png │ └── continuous-flow-memory-layout.png.license ├── Media eXchange Layer.png.license ├── The Media Exchange Layer, a crucial component in a Dynamic Media Facility.pdf ├── The Media Exchange Layer, a crucial component in a Dynamic Media Facility.pdf.license ├── Configuration.md └── Addressability.md ├── lib ├── tests │ ├── data │ │ ├── ST2110-40-Closed_Captions.cap │ │ ├── audio_flow.json.license │ │ ├── data_flow.json.license │ │ ├── v210_flow.json.license │ │ ├── v210a_flow.json.license │ │ ├── ST2110-40-Closed_Captions.cap.license │ │ ├── data_flow.json │ │ ├── audio_flow.json │ │ ├── v210_flow.json │ │ └── v210a_flow.json │ ├── fabrics │ │ ├── CMakeLists.txt │ │ └── ofi │ │ │ ├── test_Address.cpp │ │ │ ├── test_Provider.cpp │ │ │ ├── CMakeLists.txt │ │ │ └── test_Region.cpp │ ├── all_headers.c │ ├── test_pkgconfig_c_link.sh │ └── test_time.cpp ├── cmake │ ├── libmxl.pc.in.license │ ├── mxl-config.cmake.in │ └── libmxl.pc.in ├── fabrics │ ├── ofi │ │ ├── cmake │ │ │ ├── libmxl-fabrics.pc.in.license │ │ │ ├── mxl-fabrics-config.cmake.in.license │ │ │ ├── libmxl-fabrics.pc.in │ │ │ └── mxl-fabrics-config.cmake.in │ │ └── src │ │ │ └── internal │ │ │ ├── FabricVersion.hpp │ │ │ ├── FabricVersion.cpp │ │ │ ├── VariantUtils.hpp │ │ │ ├── Provider.hpp │ │ │ ├── RemoteRegion.cpp │ │ │ ├── Exception.cpp │ │ │ ├── LocalRegion.cpp │ │ │ ├── RegisteredRegion.cpp │ │ │ ├── Fabric.hpp │ │ │ ├── Provider.cpp │ │ │ ├── RegisteredRegion.hpp │ │ │ ├── Fabric.cpp │ │ │ ├── Address.hpp │ │ │ ├── Format.hpp │ │ │ ├── Address.cpp │ │ │ ├── RemoteRegion.hpp │ │ │ └── MemoryRegion.hpp │ └── CMakeLists.txt ├── internal │ ├── src │ │ ├── Logging.cpp │ │ ├── MediaUtils.cpp │ │ ├── DynamicPointerCast.hpp │ │ ├── FlowWriter.cpp │ │ ├── FlowReader.cpp │ │ ├── Timing.cpp │ │ ├── Time.cpp │ │ ├── Deferred.hpp │ │ ├── PosixFlowIoFactory.cpp │ │ ├── PathUtils.cpp │ │ ├── FlowIoFactory.cpp │ │ ├── Thread.cpp │ │ ├── PosixDiscreteFlowWriter.hpp │ │ └── FlowOptionsParser.cpp │ ├── include │ │ └── mxl-internal │ │ │ ├── FlowInfo.hpp │ │ │ ├── Time.hpp │ │ │ ├── Rational.hpp │ │ │ ├── FlowIoFactory.hpp │ │ │ ├── MediaUtils.hpp │ │ │ ├── DiscreteFlowWriter.hpp │ │ │ ├── FlowReaderFactory.hpp │ │ │ ├── FlowWriterFactory.hpp │ │ │ ├── ContinuousFlowWriter.hpp │ │ │ ├── detail │ │ │ └── ClockHelpers.hpp │ │ │ ├── PosixFlowIoFactory.hpp │ │ │ ├── FlowState.hpp │ │ │ ├── Sync.hpp │ │ │ ├── Thread.hpp │ │ │ ├── Flow.hpp │ │ │ ├── FlowOptionsParser.hpp │ │ │ ├── DiscreteFlowReader.hpp │ │ │ ├── ContinuousFlowReader.hpp │ │ │ └── FlowWriter.hpp │ └── tests │ │ └── CMakeLists.txt ├── include │ └── mxl │ │ ├── rational.h │ │ ├── version.h.in │ │ ├── platform.h │ │ └── dataformat.h └── src │ ├── time.cpp │ └── mxl.cpp ├── vcpkg.json.license ├── CMakePresets.json.license ├── utils ├── CMakeLists.txt └── gst-looping-filesrc │ ├── gst-looping-filesrc.h │ ├── README.md │ └── CMakeLists.txt ├── .github └── ISSUE_TEMPLATE │ ├── config.yml │ ├── tsc-meeting-topic.md │ ├── task.yml │ ├── feature_request.md │ ├── bug_report.md │ └── feature.yml ├── .gitignore ├── tools ├── CMakeLists.txt ├── mxl-fabrics-demo │ └── CMakeLists.txt └── mxl-info │ └── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── .clang-tidy ├── .clangd ├── .devcontainer ├── scripts │ └── common │ │ ├── libfabric │ │ └── install.sh │ │ └── rust │ │ └── install-rust.sh ├── Dockerfile.amazonlinux ├── Dockerfile.almalinux ├── amazonlinux │ └── devcontainer.json ├── almalinux │ └── devcontainer.json ├── debiantrixie │ └── devcontainer.json ├── ubuntu24 │ └── devcontainer.json ├── ubuntu26 │ └── devcontainer.json ├── ubuntu20 │ └── devcontainer.json ├── ubuntu22 │ └── devcontainer.json ├── Dockerfile.debiantrixie └── Dockerfile ├── examples ├── Dockerfile.reader.txt ├── Dockerfile.writer.txt ├── docker-compose.yaml ├── kube-deployment.yaml └── README.md ├── SECURITY.md ├── .vscode ├── tasks.json ├── launch.json └── settings.json ├── cmake └── modules │ └── Findpicojson.cmake ├── vcpkg.json ├── LICENSES └── MIT.txt └── Doxyfile.in /rust/flake.lock: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /GOVERNANCE/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /GOVERNANCE/CHARTER.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/GOVERNANCE/CHARTER.pdf -------------------------------------------------------------------------------- /docs/Media eXchange Layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/docs/Media eXchange Layer.png -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-rma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/docs/fabrics/img/mxl-fabrics-rma.png -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/docs/fabrics/img/mxl-fabrics-overview.png -------------------------------------------------------------------------------- /docs/logo/png/mxl-on-blue-square-128px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/docs/logo/png/mxl-on-blue-square-128px.png -------------------------------------------------------------------------------- /docs/assets/continuous-flow-memory-layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/docs/assets/continuous-flow-memory-layout.png -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-bouncebuffer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/docs/fabrics/img/mxl-fabrics-bouncebuffer.png -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-grain-layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/docs/fabrics/img/mxl-fabrics-grain-layout.png -------------------------------------------------------------------------------- /lib/tests/data/ST2110-40-Closed_Captions.cap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/lib/tests/data/ST2110-40-Closed_Captions.cap -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-cont-flow-rma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/docs/fabrics/img/mxl-fabrics-cont-flow-rma.png -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-rma-with-alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/docs/fabrics/img/mxl-fabrics-rma-with-alpha.png -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-cont-flow-layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/docs/fabrics/img/mxl-fabrics-cont-flow-layout.png -------------------------------------------------------------------------------- /vcpkg.json.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /CMakePresets.json.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /GOVERNANCE/CHARTER.pdf.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /lib/cmake/libmxl.pc.in.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /rust/Cargo.lock.license: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /GOVERNANCE/MXL-Requirement-Feature-Workflow-2025-10-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/GOVERNANCE/MXL-Requirement-Feature-Workflow-2025-10-09.png -------------------------------------------------------------------------------- /docs/logo/mxl-on-blue-square.svg.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /docs/Media eXchange Layer.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /docs/logo/mxl-on-blue-rectangular.svg.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /docs/logo/mxl-on-white-square.svg.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /lib/tests/data/audio_flow.json.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /lib/tests/data/data_flow.json.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /lib/tests/data/v210_flow.json.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /lib/tests/data/v210a_flow.json.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-rma.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /docs/logo/mxl-on-white-rectangular.svg.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /docs/logo/png/mxl-on-blue-square-128px.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /rust/mxl-sys/.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | mxl/version.h 5 | -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-overview.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /docs/logo/mxl-on-blue-rectangular-supporter.svg.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/cmake/libmxl-fabrics.pc.in.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /rust/.gitattributes: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | Cargo.lock -diff 5 | -------------------------------------------------------------------------------- /docs/assets/continuous-flow-memory-layout.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-bouncebuffer.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-cont-flow-rma.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-grain-layout.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-rma-with-alpha.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /lib/tests/data/ST2110-40-Closed_Captions.cap.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /docs/fabrics/img/mxl-fabrics-cont-flow-layout.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/cmake/mxl-fabrics-config.cmake.in.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /GOVERNANCE/MXL-Requirement-Feature-Workflow-2025-10-09.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_subdirectory(gst-looping-filesrc) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | 3 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /lib/internal/src/Logging.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl-internal/Logging.hpp" 5 | -------------------------------------------------------------------------------- /rust/.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | .DS_Store 5 | .idea 6 | .vscode 7 | target 8 | -------------------------------------------------------------------------------- /docs/The Media Exchange Layer, a crucial component in a Dynamic Media Facility.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmf-mxl/mxl/HEAD/docs/The Media Exchange Layer, a crucial component in a Dynamic Media Facility.pdf -------------------------------------------------------------------------------- /docs/The Media Exchange Layer, a crucial component in a Dynamic Media Facility.pdf.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /lib/tests/fabrics/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | if (MXL_ENABLE_FABRICS_OFI) 5 | add_subdirectory(ofi) 6 | endif () 7 | -------------------------------------------------------------------------------- /rust/mxl-sys/wrapper-with-version-h.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "wrapper-without-version-h.h" 5 | #include "mxl/version.h" 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | build 5 | .cache 6 | install 7 | 8 | CMakeUserPresets.json 9 | 10 | .idea 11 | .vscode 12 | -------------------------------------------------------------------------------- /rust/mxl/src/grain.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub mod data; 5 | pub mod reader; 6 | pub mod write_access; 7 | pub mod writer; 8 | -------------------------------------------------------------------------------- /rust/mxl/src/samples.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub mod data; 5 | pub mod reader; 6 | pub mod write_access; 7 | pub mod writer; 8 | -------------------------------------------------------------------------------- /rust/.config/nextest.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | [profile.ci] 5 | fail-fast = false 6 | 7 | [profile.ci.junit] 8 | path = "junit.xml" 9 | -------------------------------------------------------------------------------- /lib/cmake/mxl-config.cmake.in: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | @PACKAGE_INIT@ 5 | 6 | if(NOT TARGET mxl::mxl) 7 | include("${CMAKE_CURRENT_LIST_DIR}/mxl-targets.cmake") 8 | endif() -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_subdirectory(mxl-info) 5 | add_subdirectory(mxl-gst) 6 | 7 | if (MXL_ENABLE_FABRICS_OFI) 8 | add_subdirectory(mxl-fabrics-demo) 9 | endif () 10 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Code of conduct 5 | 6 | The Linux Foundation Projects Code of Conduct listed at applies to all Collaborators in the MXL Project. 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/tsc-meeting-topic.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: TSC Meeting Topic 3 | about: Covers a topic discussed in the TSC weekly meeting 4 | title: "[TSC]" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lib/tests/all_headers.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // Simple test to ensure all headers are valid according to the C17 standard 9 | int main(void) 10 | { 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/FlowInfo.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | MXL_EXPORT 11 | std::ostream& operator<<(std::ostream& os, mxlFlowInfo const& obj); 12 | -------------------------------------------------------------------------------- /rust/mxl-sys/wrapper-without-version-h.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl/dataformat.h" 5 | #include "mxl/flow.h" 6 | #include "mxl/flowinfo.h" 7 | #include "mxl/mxl.h" 8 | #include "mxl/platform.h" 9 | #include "mxl/rational.h" 10 | #include "mxl/time.h" 11 | -------------------------------------------------------------------------------- /lib/cmake/libmxl.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@MXL_PKGCONFIG_PREFIX@ 2 | exec_prefix=${prefix} 3 | libdir=@MXL_PKGCONFIG_LIBDIR@ 4 | includedir=@MXL_PKGCONFIG_INCLUDEDIR@ 5 | 6 | Name: libmxl 7 | Version: @PROJECT_VERSION@ 8 | Description: Media eXchange Layer SDK 9 | Libs: -L${libdir} -lmxl 10 | Requires.private: spdlog 11 | Libs.private: -pthread -lmxl-common -lstdc++ -lm 12 | Cflags: -I${includedir} 13 | 14 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | Checks: "-*,modernize-*,-modernize-use-trailing-return-type" 5 | HeaderFileExtensions: ["", "h", "hpp"] 6 | ImplementationFileExtensions: ["cpp"] 7 | CheckOptions: 8 | modernize-use-using.IgnoreExternC: "true" 9 | modernize-use-using.IgnoreMacros: "true" 10 | -------------------------------------------------------------------------------- /.clangd: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | Diagnostics: 5 | UnusedIncludes: Strict 6 | MissingIncludes: None 7 | Index: 8 | StandardLibrary: Yes 9 | Hover: 10 | ShowAKA: Yes 11 | InlayHints: 12 | Designators: Yes 13 | Enabled: Yes 14 | ParameterNames: Yes 15 | DeducedTypes: Yes 16 | BlockEnd: Yes 17 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/FabricVersion.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace mxl::lib::fabrics::ofi 10 | { 11 | /** \brief Returns the libfabric version this library was compiled with. 12 | */ 13 | std::uint32_t fiVersion() noexcept; 14 | } 15 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/FabricVersion.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "FabricVersion.hpp" 6 | #include 7 | 8 | namespace mxl::lib::fabrics::ofi 9 | { 10 | std::uint32_t fiVersion() noexcept 11 | { 12 | return FI_VERSION(FI_MAJOR_VERSION, FI_MINOR_VERSION); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/cmake/libmxl-fabrics.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=${prefix} 3 | libdir=@CMAKE_INSTALL_FULL_LIBDIR@ 4 | includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ 5 | 6 | Name: libmxl-fabrics 7 | Version: @PROJECT_VERSION@ 8 | Requires: libmxl libfabric 9 | Description: Media eXchange Layer SDK Fabrics library 10 | Libs: -L${libdir} -lmxl-fabrics 11 | Libs.private: -pthread 12 | Cflags: -I${includedir} 13 | 14 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/VariantUtils.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | namespace mxl::lib::fabrics::ofi 8 | { 9 | // Allows us to use the visitor pattern with lambdas 10 | template 11 | struct overloaded : Ts... 12 | { 13 | using Ts::operator()...; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /rust/mxl-sys/tests/simple_test.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #[test] 5 | fn there_is_bindgen_generated_code() { 6 | let mxl_version = mxl_sys::VersionType { 7 | major: 3, 8 | minor: 2, 9 | bugfix: 1, 10 | ..Default::default() 11 | }; 12 | 13 | println!("mxl_version: {:?}", mxl_version); 14 | } 15 | -------------------------------------------------------------------------------- /rust/mxl/examples/common/mod.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub fn setup_logging() { 5 | tracing_subscriber::fmt() 6 | .with_env_filter( 7 | tracing_subscriber::EnvFilter::builder() 8 | .with_default_directive(tracing::level_filters::LevelFilter::INFO.into()) 9 | .from_env_lossy(), 10 | ) 11 | .init(); 12 | } 13 | -------------------------------------------------------------------------------- /rust/mxl-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | [package] 5 | name = "mxl-sys" 6 | edition.workspace = true 7 | publish.workspace = true 8 | version.workspace = true 9 | license.workspace = true 10 | 11 | [dependencies] 12 | libloading.workspace = true 13 | 14 | [build-dependencies] 15 | bindgen.workspace = true 16 | cmake = "0.1.54" 17 | 18 | [features] 19 | mxl-not-built = [] 20 | -------------------------------------------------------------------------------- /.devcontainer/scripts/common/libfabric/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | set -e 6 | set -x 7 | 8 | git clone -b v2.2.0 https://github.com/ofiwg/libfabric.git 9 | 10 | cd libfabric 11 | ./autogen.sh 12 | ./configure \ 13 | --prefix=/usr \ 14 | --disable-kdreg2 \ 15 | --disable-memhooks-monitor \ 16 | --disable-uffd-monitor 17 | 18 | make install "-j$(nproc)" 19 | -------------------------------------------------------------------------------- /rust/mxl/src/api.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use std::{path::Path, sync::Arc}; 5 | 6 | use mxl_sys::libmxl; 7 | 8 | use crate::Result; 9 | 10 | pub type MxlApi = libmxl; 11 | pub type MxlApiHandle = Arc; 12 | 13 | pub fn load_api(path_to_so_file: impl AsRef) -> Result { 14 | Ok(Arc::new(unsafe { 15 | libmxl::new(path_to_so_file.as_ref().as_os_str())? 16 | })) 17 | } 18 | -------------------------------------------------------------------------------- /lib/include/mxl/rational.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #ifdef __cplusplus 7 | # include 8 | #else 9 | # include 10 | #endif 11 | 12 | #ifdef __cplusplus 13 | extern "C" 14 | { 15 | #endif 16 | 17 | typedef struct mxlRational_t 18 | { 19 | int64_t numerator; 20 | int64_t denominator; 21 | } mxlRational; 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /lib/include/mxl/version.h.in: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #define MXL_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ 7 | #define MXL_VERSION_MINOR @PROJECT_VERSION_MINOR@ 8 | #define MXL_VERSION_PATCH @PROJECT_VERSION_PATCH@ 9 | #define MXL_VERSION_BUILD @PROJECT_VERSION_TWEAK@ 10 | #define MXL_VERSION_FULL "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@@MXL_BUILD_SUFFIX@+@PROJECT_VERSION_TWEAK@ g@GIT_HASH@" 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/task.yml: -------------------------------------------------------------------------------- 1 | name: Task 2 | description: Create a new task 3 | labels: [ Task ] 4 | assignees: [] 5 | title: "[Task] " 6 | 7 | body: 8 | - type: textarea 9 | id: description 10 | attributes: 11 | label: Description 12 | description: A clear and concise description of the task 13 | placeholder: "Describe the task" 14 | validations: 15 | required: true 16 | 17 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 18 | # SPDX-License-Identifier: Apache-2.0 19 | 20 | -------------------------------------------------------------------------------- /lib/internal/src/MediaUtils.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl-internal/MediaUtils.hpp" 5 | #include 6 | 7 | MXL_EXPORT 8 | std::uint32_t mxl::lib::getV210LineLength(std::size_t width) 9 | { 10 | return static_cast((width + 47) / 48 * 128); 11 | } 12 | 13 | MXL_EXPORT 14 | std::uint32_t mxl::lib::get10BitAlphaLineLength(std::size_t width) 15 | { 16 | return static_cast((width + 2) / 3 * 4); 17 | } 18 | -------------------------------------------------------------------------------- /examples/Dockerfile.reader.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | FROM debian:trixie-slim 5 | 6 | WORKDIR /app 7 | 8 | RUN apt update && apt-get -y install\ 9 | procps \ 10 | patchelf && rm -rf /var/lib/apt/lists/* 11 | 12 | COPY build/Linux-Clang-Release/lib/*.so* /app/ 13 | COPY build/Linux-Clang-Release/tools/mxl-info/mxl-info /app/ 14 | 15 | RUN patchelf --set-rpath /app mxl-info 16 | 17 | CMD["sh", "-c", "while true; do /app/mxl-info -d /domain -l || true; sleep 2; done"] 18 | -------------------------------------------------------------------------------- /lib/internal/src/DynamicPointerCast.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | 7 | namespace mxl::lib 8 | { 9 | template 10 | std::unique_ptr dynamic_pointer_cast(std::unique_ptr&& source) noexcept 11 | { 12 | auto const p = dynamic_cast(source.get()); 13 | if (p != nullptr) 14 | { 15 | source.release(); 16 | } 17 | return std::unique_ptr{p}; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/include/mxl/platform.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #if defined(__GNUC__) || defined(__clang__) 7 | # define MXL_EXPORT __attribute__((visibility("default"))) 8 | #else 9 | # define MXL_EXPORT 10 | #endif 11 | 12 | // TODO: Tailor these more to specific language statdard levels 13 | #ifdef __cplusplus 14 | # define MXL_NODISCARD [[nodiscard]] 15 | # define MXL_CONSTEXPR constexpr 16 | #else 17 | # define MXL_NODISCARD 18 | # define MXL_CONSTEXPR inline 19 | #endif 20 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/Time.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | bool operator==(timespec const& lhs, timespec const& rhs); 9 | 10 | bool operator!=(timespec const& lhs, timespec const& rhs); 11 | 12 | bool operator<(timespec const& lhs, timespec const& rhs); 13 | 14 | bool operator<=(timespec const& lhs, timespec const& rhs); 15 | 16 | bool operator>(timespec const& lhs, timespec const& rhs); 17 | 18 | bool operator>=(timespec const& lhs, timespec const& rhs); 19 | -------------------------------------------------------------------------------- /lib/internal/src/FlowWriter.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl-internal/FlowWriter.hpp" 5 | #include 6 | 7 | namespace mxl::lib 8 | { 9 | FlowWriter::FlowWriter(uuids::uuid&& flowId) 10 | : _flowId{std::move(flowId)} 11 | {} 12 | 13 | FlowWriter::FlowWriter(uuids::uuid const& flowId) 14 | : _flowId{flowId} 15 | {} 16 | 17 | FlowWriter::FlowWriter::~FlowWriter() = default; 18 | 19 | uuids::uuid const& FlowWriter::getId() const 20 | { 21 | return _flowId; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rust/mxl/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | [package] 5 | name = "mxl" 6 | edition.workspace = true 7 | publish.workspace = true 8 | version.workspace = true 9 | license.workspace = true 10 | 11 | [dependencies] 12 | mxl-sys = { path = "../mxl-sys" } 13 | 14 | libloading.workspace = true 15 | thiserror.workspace = true 16 | tracing.workspace = true 17 | uuid.workspace = true 18 | 19 | [dev-dependencies] 20 | clap.workspace = true 21 | tracing-subscriber.workspace = true 22 | 23 | [features] 24 | mxl-not-built = ["mxl-sys/mxl-not-built"] 25 | -------------------------------------------------------------------------------- /rust/deny.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # This section is considered when running `cargo deny check licenses` 5 | # More documentation for the licenses section can be found here: 6 | # https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html 7 | [licenses] 8 | # List of explicitly allowed licenses 9 | # See https://spdx.org/licenses/ for list of possible licenses 10 | # [possible values: any SPDX 3.11 short identifier (+ optional exception)]. 11 | allow = [ 12 | "MIT", 13 | "Apache-2.0", 14 | "Unicode-3.0", 15 | "BSD-3-Clause", 16 | "ISC" 17 | ] 18 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/Rational.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | constexpr bool isValid(mxlRational const& rational) noexcept 9 | { 10 | return (rational.denominator != 0); 11 | } 12 | 13 | constexpr bool operator==(mxlRational const& lhs, mxlRational const& rhs) noexcept 14 | { 15 | return (lhs.numerator * rhs.denominator) == (lhs.denominator * rhs.numerator); 16 | } 17 | 18 | constexpr bool operator!=(mxlRational const& lhs, mxlRational const& rhs) noexcept 19 | { 20 | return !(lhs == rhs); 21 | } 22 | -------------------------------------------------------------------------------- /rust/mxl/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | mod api; 5 | mod error; 6 | mod flow; 7 | mod grain; 8 | mod instance; 9 | mod samples; 10 | 11 | pub mod config; 12 | 13 | pub use api::{MxlApi, load_api}; 14 | pub use error::{Error, Result}; 15 | pub use flow::{reader::FlowReader, writer::FlowWriter, *}; 16 | pub use grain::{ 17 | data::*, reader::GrainReader, write_access::GrainWriteAccess, writer::GrainWriter, 18 | }; 19 | pub use instance::MxlInstance; 20 | pub use samples::{ 21 | data::*, reader::SamplesReader, write_access::SamplesWriteAccess, writer::SamplesWriter, 22 | }; 23 | -------------------------------------------------------------------------------- /rust/mxl-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Suppress expected warnings from bindgen-generated code. 5 | // See https://github.com/rust-lang/rust-bindgen/issues/1651. 6 | 7 | #![allow(non_upper_case_globals)] 8 | #![allow(non_camel_case_types)] 9 | #![allow(non_snake_case)] 10 | #![allow(missing_docs)] 11 | #![allow(rustdoc::broken_intra_doc_links)] 12 | #![allow(rustdoc::invalid_html_tags)] 13 | #![allow(unsafe_op_in_unsafe_fn)] 14 | #![allow(deref_nullptr)] 15 | #![allow(clippy::missing_safety_doc)] 16 | 17 | extern crate libloading; 18 | 19 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 20 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Security Policy 5 | 6 | ## Reporting a Vulnerability 7 | 8 | To report vulnerabilities, you can privately report a potential security issue via the GitHub security vulnerabilities feature. This can be done here: 9 | 10 | 11 | Please do not open a public issue about a potential security vulnerability. 12 | You can find more details on the security vulnerability feature in the GitHub documentation here: 13 | 14 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project https://github.com/dmf-mxl/mxl/contributors.md 2 | // SPDX-License-Identifier: Apache-2.0 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "cmake", 8 | "label": "CMake: build", 9 | "command": "build", 10 | "targets": [ 11 | "all" 12 | ], 13 | "preset": "${command:cmake.activeBuildPresetName}", 14 | "group": "build", 15 | "problemMatcher": [], 16 | "detail": "CMake template build task" 17 | }, 18 | { 19 | "type": "cmake", 20 | "label": "CMake: clean", 21 | "command": "clean", 22 | "preset": "${command:cmake.activeBuildPresetName}", 23 | "problemMatcher": [], 24 | "detail": "CMake template clean task" 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /lib/tests/data/data_flow.json: -------------------------------------------------------------------------------- 1 | { 2 | "$copyright": "SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project.", 3 | "$license": "SPDX-License-Identifier: Apache-2.0", 4 | "description": "MXL VANC Data", 5 | "tags": { 6 | "urn:x-nmos:tag:grouphint/v1.0": [ 7 | "Media Function XYZ:Ancillary Data" 8 | ] 9 | }, 10 | "format": "urn:x-nmos:format:data", 11 | "label": "MXL VANC Data", 12 | "version": "1453880607:123995943", 13 | "parents": [], 14 | "source_id": "0e635152-e501-4d4e-bb87-9f3fe05eb79a", 15 | "device_id": "9126cc2f-4c26-4c9b-a6cd-93c4381c9be5", 16 | "id": "db3bd465-2772-484f-8fac-830b0471258b", 17 | "media_type": "video/smpte291", 18 | "grain_rate": { 19 | "numerator": 30000, 20 | "denominator": 1001 21 | } 22 | } -------------------------------------------------------------------------------- /examples/Dockerfile.writer.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | FROM debian:trixie-slim 5 | 6 | WORKDIR /app 7 | 8 | RUN apt update && apt-get -y install\ 9 | gstreamer1.0-plugins-good\ 10 | gstreamer1.0-x \ 11 | patchelf && rm -rf /var/lib/apt/lists/* 12 | 13 | COPY build/Linux-Clang-Release/lib/*.so* /app/ 14 | COPY build/Linux-Clang-Release/lib/internal/*.so* /app/ 15 | COPY build/Linux-Clang-Release/lib/tests/data/*.json /app/ 16 | COPY build/Linux-Clang-Release/tools/mxl-gst/mxl-gst-testsrc /app/ 17 | 18 | RUN patchelf --set-rpath /app mxl-gst-testsrc 19 | 20 | CMD ["/app/mxl-gst-testsrc", "-d", "/domain", "-v", "/app/v210_flow.json", "-a", "/app/audio_flow.json"] 21 | -------------------------------------------------------------------------------- /lib/tests/data/audio_flow.json: -------------------------------------------------------------------------------- 1 | { 2 | "$copyright": "SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project.", 3 | "$license": "SPDX-License-Identifier: Apache-2.0", 4 | "description": "MXL Audio Flow", 5 | "format": "urn:x-nmos:format:audio", 6 | "tags": { 7 | "urn:x-nmos:tag:grouphint/v1.0": [ 8 | "Media Function XYZ:Audio" 9 | ] 10 | }, 11 | "label": "MXL Audio Flow", 12 | "version": "1441812152:154331951", 13 | "id": "b3bb5be7-9fe9-4324-a5bb-4c70e1084449", 14 | "media_type": "audio/float32", 15 | "sample_rate": { 16 | "numerator": 48000 17 | }, 18 | "channel_count": 2, 19 | "bit_depth": 32, 20 | "parents": [], 21 | "source_id": "2aa143ac-0ab7-4d75-bc32-5c00c13d186f", 22 | "device_id": "169feb2c-3fae-42a5-ae2e-f6f8cbce29cf" 23 | } 24 | -------------------------------------------------------------------------------- /cmake/modules/Findpicojson.cmake: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | find_path(picojson_INCLUDE_DIR NAMES picojson/picojson.h DOC "The picojson include directory") 5 | mark_as_advanced(picojson_INCLUDE_DIR) 6 | 7 | include(FindPackageHandleStandardArgs) 8 | find_package_handle_standard_args(picojson 9 | FOUND_VAR picojson_FOUND 10 | REQUIRED_VARS picojson_INCLUDE_DIR 11 | ) 12 | 13 | if(picojson_FOUND) 14 | set(picojson_INCLUDE_DIRS ${picojson_INCLUDE_DIR}) 15 | if(NOT TARGET picojson::picojson) 16 | add_library(picojson::picojson INTERFACE IMPORTED) 17 | set_target_properties(picojson::picojson PROPERTIES 18 | INTERFACE_INCLUDE_DIRECTORIES "${picojson_INCLUDE_DIRS}" 19 | ) 20 | endif() 21 | endif() 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/FlowIoFactory.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include "FlowReaderFactory.hpp" 7 | #include "FlowWriterFactory.hpp" 8 | 9 | namespace mxl::lib 10 | { 11 | class MXL_EXPORT FlowIoFactory 12 | : public FlowReaderFactory 13 | , public FlowWriterFactory 14 | { 15 | public: 16 | std::unique_ptr createFlowReader(FlowManager const& manager, uuids::uuid const& flowId, std::unique_ptr&& data); 17 | std::unique_ptr createFlowWriter(FlowManager const& manager, uuids::uuid const& flowId, std::unique_ptr&& data); 18 | 19 | virtual ~FlowIoFactory(); 20 | 21 | protected: 22 | FlowIoFactory(); 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /lib/fabrics/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | include(GNUInstallDirs) 5 | 6 | add_library(mxl-fabrics-headers INTERFACE) 7 | 8 | target_include_directories(mxl-fabrics-headers 9 | INTERFACE 10 | $ 11 | $ 12 | ) 13 | 14 | install(TARGETS mxl-fabrics-headers EXPORT ${PROJECT_NAME}-targets 15 | COMPONENT ${PROJECT_NAME}-dev 16 | ) 17 | 18 | install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" 19 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 20 | COMPONENT ${PROJECT_NAME}-dev 21 | FILES_MATCHING 22 | PATTERN "*.h" 23 | ) 24 | 25 | if (MXL_ENABLE_FABRICS_OFI) 26 | add_subdirectory(ofi) 27 | endif () 28 | 29 | -------------------------------------------------------------------------------- /lib/internal/src/FlowReader.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl-internal/FlowReader.hpp" 5 | #include 6 | 7 | namespace mxl::lib 8 | { 9 | FlowReader::FlowReader(uuids::uuid&& flowId, std::filesystem::path const& domain) 10 | : _flowId{std::move(flowId)} 11 | , _domain{domain} 12 | {} 13 | 14 | FlowReader::FlowReader(uuids::uuid const& flowId, std::filesystem::path const& domain) 15 | : _flowId{flowId} 16 | , _domain{domain} 17 | {} 18 | 19 | FlowReader::FlowReader::~FlowReader() = default; 20 | 21 | uuids::uuid const& FlowReader::getId() const 22 | { 23 | return _flowId; 24 | } 25 | 26 | std::filesystem::path const& FlowReader::getDomain() const 27 | { 28 | return _domain; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /GOVERNANCE/DoD.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # MXL Definition of Done (DoD) 5 | 6 | DONE Feature or Bug fix 7 | 8 | 1. PR has been reviewed by at least 2 reviewers from the TSC 9 | - Has been code peer reviewed 10 | - Included in the release note 11 | - Has just enough documentation to understand what it is doing and how this should be used 12 | - Has been seen working in a simple scenario 13 | - Include most relevant unit automated tests 14 | 15 | 2. (Feature only) Implemented Feature has been reviewed by at least two members of the Requirement Council 16 | - Feature demonstrated or tried out 17 | - Feature is accepted as adressing the corresponding Requirement 18 | - Documentation is clear enough for the users 19 | - Requirement is closed 20 | 21 | 3. PR has been merged in the main branch by a Maintainer 22 | -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", 3 | "dependencies": [ 4 | { 5 | "name": "catch2", 6 | "version>=": "3.11.0#0" 7 | }, 8 | { 9 | "name": "stduuid", 10 | "version>=": "1.2.3", 11 | "features": [ 12 | "system-gen", 13 | "gsl-span" 14 | ] 15 | }, 16 | { 17 | "name": "spdlog", 18 | "version>=": "1.16.0#0" 19 | }, 20 | { 21 | "name": "fmt", 22 | "version>=": "12.1.0#0" 23 | }, 24 | { 25 | "name": "picojson", 26 | "version>=": "1.3.0#3" 27 | }, 28 | { 29 | "name": "cli11", 30 | "version>=": "2.6.1#0" 31 | }, 32 | { 33 | "name": "pcapplusplus", 34 | "version>=": "25.5#0", 35 | "platform": "linux" 36 | } 37 | ], 38 | "builtin-baseline": "4002e3abc6d3e468c73d2d9777a7dd96af5dc224" 39 | } -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/MediaUtils.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace mxl::lib 10 | { 11 | /** 12 | * Length in bytes of a line in the V210 video format. 13 | * @param width The width of the video frame in pixels. 14 | * @return The line length in bytes for the V210 format, including padding. 15 | */ 16 | std::uint32_t getV210LineLength(std::size_t width); 17 | 18 | /** 19 | * Length in bytes of a line in the 10-bit alpha video format (3x10-bit samples per 32 bit word). 20 | * @param width The width of the video frame in pixels. 21 | * @return The line length in bytes for the 10-bit Alpha format, including padding. 22 | */ 23 | std::uint32_t get10BitAlphaLineLength(std::size_t width); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /docs/Configuration.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Configuration 5 | 6 | ## Domain level configuration 7 | 8 | Domain level configuration is stored in an optional 'options.json' files stored at the root of the MXL domain. If present, the MXL SDK will look for specific options defined in the table below and configure itself accordingly. 9 | 10 | | Option | Description | Default Value | 11 | |----------------|---------------------------|---------------| 12 | | `urn:x-mxl:option:history_duration/v1.0"` | Depth, in nanoseconds, of a ringbuffer | 200'000'000ns | 13 | 14 | ### Example 'options.json' file 15 | 16 | This options file will configure the depth of the ringbuffers to 500'000'000ns (500ms) 17 | 18 | ```json 19 | { 20 | "urn:x-mxl:option:history_duration/v1.0": 500000000 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/DiscreteFlowWriter.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include "FlowWriter.hpp" 7 | 8 | namespace mxl::lib 9 | { 10 | class MXL_EXPORT DiscreteFlowWriter : public FlowWriter 11 | { 12 | public: 13 | /** 14 | * Get the grain info for a specific grain index without opening the grain for mutation. 15 | */ 16 | [[nodiscard]] 17 | virtual mxlGrainInfo getGrainInfo(std::uint64_t in_index) const = 0; 18 | 19 | virtual mxlStatus openGrain(std::uint64_t in_index, mxlGrainInfo* out_grainInfo, std::uint8_t** out_payload) = 0; 20 | 21 | virtual mxlStatus commit(mxlGrainInfo const& mxlGrainInfo) = 0; 22 | 23 | virtual mxlStatus cancel() = 0; 24 | 25 | protected: 26 | using FlowWriter::FlowWriter; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /rust/mxl/src/config.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use std::str::FromStr; 5 | 6 | include!(concat!(env!("OUT_DIR"), "/constants.rs")); 7 | 8 | #[cfg(not(feature = "mxl-not-built"))] 9 | pub fn get_mxl_so_path() -> std::path::PathBuf { 10 | // The mxl-sys build script ensures that the build directory is in the library path 11 | // so we can just return the library name here. 12 | "libmxl.so".into() 13 | } 14 | 15 | #[cfg(feature = "mxl-not-built")] 16 | pub fn get_mxl_so_path() -> std::path::PathBuf { 17 | std::path::PathBuf::from_str(MXL_BUILD_DIR) 18 | .expect("build error: 'MXL_BUILD_DIR' is invalid") 19 | .join("lib") 20 | .join("libmxl.so") 21 | } 22 | 23 | pub fn get_mxl_repo_root() -> std::path::PathBuf { 24 | std::path::PathBuf::from_str(MXL_REPO_ROOT).expect("build error: 'MXL_REPO_ROOT' is invalid") 25 | } 26 | -------------------------------------------------------------------------------- /lib/internal/src/Timing.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl-internal/Timing.hpp" 5 | #include 6 | #include "mxl-internal/detail/ClockHelpers.hpp" 7 | 8 | namespace mxl::lib 9 | { 10 | MXL_EXPORT 11 | Timepoint currentTime(Clock clock) noexcept 12 | { 13 | auto result = Timepoint{}; 14 | 15 | std::timespec ts; 16 | if (::clock_gettime(detail::clockToId(clock), &ts) == 0) 17 | { 18 | result = asTimepoint(ts) + detail::getClockOffset(clock); 19 | } 20 | return result; 21 | } 22 | 23 | Timepoint currentTimeUTC() noexcept 24 | { 25 | auto result = Timepoint{}; 26 | 27 | std::timespec ts; 28 | if (::timespec_get(&ts, TIME_UTC) != 0) 29 | { 30 | result = asTimepoint(ts); 31 | } 32 | return result; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/FlowReaderFactory.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include "ContinuousFlowData.hpp" 8 | #include "ContinuousFlowReader.hpp" 9 | #include "DiscreteFlowData.hpp" 10 | #include "DiscreteFlowReader.hpp" 11 | 12 | namespace mxl::lib 13 | { 14 | class FlowManager; 15 | 16 | class FlowReaderFactory 17 | { 18 | public: 19 | virtual std::unique_ptr createDiscreteFlowReader(FlowManager const& manager, uuids::uuid const& flowId, 20 | std::unique_ptr&& data) const = 0; 21 | virtual std::unique_ptr createContinuousFlowReader(FlowManager const& manager, uuids::uuid const& flowId, 22 | std::unique_ptr&& data) const = 0; 23 | 24 | protected: 25 | ~FlowReaderFactory() = default; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /rust/README.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # Rust bindings for DMF MXL 7 | 8 | ## Goals 9 | 10 | - Hide all the unsafe stuff inside these bindings. 11 | - Provide more Rust-native like experience (async API based on `futures::stream` and 12 | `futures::sink`?). 13 | 14 | ## Code Guidelines 15 | 16 | - Use `rustfmt` in it's default settings for code formatting. 17 | - The `cargo clippy` should be always clean. 18 | - Try to avoid adding more dependencies, unless really necessary. 19 | - Never use `unwrap`, `expect`, or a similar construct that causes a panic. Always return errors. Tests are an exception. 20 | 21 | ## Building 22 | 23 | - `cargo build` 24 | 25 | ## TODO 26 | 27 | - Get rid of the headers copy. Use the main headers as part of the build process. 28 | - Change the tests so they can use libraries build from the main repo. 29 | - Setup CI/CD. 30 | - Extend the functionality. 31 | -------------------------------------------------------------------------------- /.devcontainer/scripts/common/rust/install-rust.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | set -eu 7 | 8 | RUST_VERSION=1.90.0 9 | 10 | if command -v rustup >/dev/null 2>&1; then 11 | rustup default $RUST_VERSION 12 | else 13 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain=$RUST_VERSION 14 | . "$HOME/.cargo/env" 15 | fi 16 | 17 | # Install cargo binstall 18 | curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash 19 | 20 | cargo binstall cargo-audit@0.22.0 --locked 21 | cargo binstall cargo-outdated --locked 22 | 23 | # udeps requires the nightly compiler, so using machete (at least for now) 24 | # cargo binstall cargo-udeps --locked 25 | cargo binstall cargo-machete --locked 26 | 27 | cargo binstall cargo-deny --locked 28 | cargo binstall cargo-nextest --locked 29 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/FlowWriterFactory.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include "ContinuousFlowData.hpp" 9 | #include "ContinuousFlowWriter.hpp" 10 | #include "DiscreteFlowData.hpp" 11 | #include "DiscreteFlowWriter.hpp" 12 | 13 | namespace mxl::lib 14 | { 15 | class FlowManager; 16 | 17 | class FlowWriterFactory 18 | { 19 | public: 20 | virtual std::unique_ptr createDiscreteFlowWriter(FlowManager const& manager, uuids::uuid const& flowId, 21 | std::unique_ptr&& data) const = 0; 22 | virtual std::unique_ptr createContinuousFlowWriter(FlowManager const& manager, uuids::uuid const& flowId, 23 | std::unique_ptr&& data) const = 0; 24 | 25 | protected: 26 | ~FlowWriterFactory() = default; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /tools/mxl-fabrics-demo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | find_package(CLI11 CONFIG REQUIRED) 6 | find_package(stduuid CONFIG REQUIRED) 7 | find_package(spdlog CONFIG REQUIRED) 8 | 9 | # Add the test executable 10 | add_executable(mxl-fabrics-demo) 11 | target_compile_features(mxl-fabrics-demo 12 | PRIVATE 13 | cxx_std_20 14 | ) 15 | target_sources(mxl-fabrics-demo 16 | PRIVATE 17 | demo.cpp 18 | ) 19 | target_link_libraries(mxl-fabrics-demo 20 | PRIVATE 21 | mxl 22 | mxl-fabrics 23 | mxl-internal-headers 24 | mxl-common 25 | stduuid 26 | CLI11::CLI11 27 | spdlog::spdlog 28 | ) 29 | set_target_properties(mxl-fabrics-demo PROPERTIES 30 | INSTALL_RPATH "$ORIGIN/../lib" 31 | ) 32 | 33 | # Install targets 34 | install(TARGETS mxl-fabrics-demo 35 | RUNTIME DESTINATION bin 36 | ) 37 | -------------------------------------------------------------------------------- /examples/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | services: 5 | init: 6 | image: alpine 7 | command: ["sh", "-c", "mkdir -p /dev/shm/mxl"] 8 | volumes: 9 | - type: bind 10 | source: /dev/shm 11 | target: /dev/shm 12 | restart: "no" 13 | 14 | writer-media-function: 15 | image: mxl-writer 16 | depends_on: 17 | - init 18 | build: 19 | context: .. 20 | dockerfile: examples/Dockerfile.writer.txt 21 | restart: unless-stopped 22 | volumes: 23 | - type: bind 24 | source: /dev/shm/mxl 25 | target: /domain 26 | 27 | reader-media-function: 28 | image: mxl-reader 29 | depends_on: 30 | - init 31 | build: 32 | context: .. 33 | dockerfile: examples/Dockerfile.reader.txt 34 | restart: unless-stopped 35 | volumes: 36 | - type: bind 37 | source: /dev/shm/mxl 38 | target: /domain 39 | stdin_open: true 40 | tty: true 41 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | [workspace] 5 | members = ["mxl", "mxl-sys"] 6 | 7 | resolver = "2" 8 | 9 | [workspace.package] 10 | edition = "2024" 11 | publish = false 12 | version = "0.1.0" 13 | license = "Apache-2.0" 14 | license-file = "../LICENSE.txt" 15 | 16 | [workspace.dependencies] 17 | bindgen = { version = "0.72", features = ["experimental"] } 18 | # Will be used later, when we get to higher level streams based interfaces. 19 | futures = "0.3" 20 | libloading = { version = "0.8.9" } 21 | thiserror = "2.0.12" 22 | tracing = { version = "0.1", features = ["log"] } 23 | tracing-subscriber = { version = "0.3.20", features = ["env-filter", "std"] } 24 | uuid = { version = "1.17", features = ["v4"] } 25 | 26 | [workspace.dependencies.clap] 27 | version = "4.1.4" 28 | default-features = false 29 | features = ["std", "derive", "cargo", "env", "help", "usage", "error-context"] 30 | 31 | [profile.release-with-debug] 32 | debug = true 33 | inherits = "release" 34 | -------------------------------------------------------------------------------- /lib/internal/src/Time.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl-internal/Time.hpp" 5 | #include 6 | 7 | bool operator==(timespec const& lhs, timespec const& rhs) 8 | { 9 | return (lhs.tv_sec == rhs.tv_sec) && (lhs.tv_nsec == rhs.tv_nsec); 10 | } 11 | 12 | bool operator!=(timespec const& lhs, timespec const& rhs) 13 | { 14 | return !(lhs == rhs); 15 | } 16 | 17 | bool operator<(timespec const& lhs, timespec const& rhs) 18 | { 19 | if (lhs.tv_sec < rhs.tv_sec) 20 | { 21 | return true; 22 | } 23 | if (lhs.tv_sec > rhs.tv_sec) 24 | { 25 | return false; 26 | } 27 | return lhs.tv_nsec < rhs.tv_nsec; 28 | } 29 | 30 | bool operator<=(timespec const& lhs, timespec const& rhs) 31 | { 32 | return (lhs < rhs) || (lhs == rhs); 33 | } 34 | 35 | bool operator>(timespec const& lhs, timespec const& rhs) 36 | { 37 | return !(lhs <= rhs); 38 | } 39 | 40 | bool operator>=(timespec const& lhs, timespec const& rhs) 41 | { 42 | return !(lhs < rhs); 43 | } 44 | -------------------------------------------------------------------------------- /rust/mxl/build.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use std::env; 5 | use std::path::PathBuf; 6 | 7 | #[cfg(debug_assertions)] 8 | const BUILD_VARIANT: &str = "Linux-Clang-Debug"; 9 | #[cfg(not(debug_assertions))] 10 | const BUILD_VARIANT: &str = "Linux-Clang-Release"; 11 | 12 | fn main() { 13 | let manifest_dir = 14 | PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("failed to get current directory")); 15 | let repo_root = manifest_dir.parent().unwrap().parent().unwrap(); 16 | let build_dir = repo_root.join("build").join(BUILD_VARIANT); 17 | 18 | let out_path = PathBuf::from(env::var("OUT_DIR").expect("failed to get output directory")) 19 | .join("constants.rs"); 20 | 21 | let data = format!( 22 | "pub const MXL_REPO_ROOT: &str = \"{}\";\n\ 23 | pub const MXL_BUILD_DIR: &str = \"{}\";\n", 24 | repo_root.to_string_lossy(), 25 | build_dir.to_string_lossy() 26 | ); 27 | std::fs::write(out_path, data).expect("Unable to write file"); 28 | } 29 | -------------------------------------------------------------------------------- /LICENSES/MIT.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 6 | associated documentation files (the "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the 9 | following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial 12 | portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 15 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 16 | EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 18 | USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /lib/tests/data/v210_flow.json: -------------------------------------------------------------------------------- 1 | { 2 | "$copyright": "SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project.", 3 | "$license": "SPDX-License-Identifier: Apache-2.0", 4 | "description": "MXL Test Flow, 1080p29", 5 | "id": "5fbec3b1-1b0f-417d-9059-8b94a47197ed", 6 | "tags": { 7 | "urn:x-nmos:tag:grouphint/v1.0": [ 8 | "Media Function XYZ:Video" 9 | ] 10 | }, 11 | "format": "urn:x-nmos:format:video", 12 | "label": "MXL Test Flow, 1080p29", 13 | "parents": [], 14 | "media_type": "video/v210", 15 | "grain_rate": { 16 | "numerator": 30000, 17 | "denominator": 1001 18 | }, 19 | "frame_width": 1920, 20 | "frame_height": 1080, 21 | "interlace_mode": "progressive", 22 | "colorspace": "BT709", 23 | "components": [ 24 | { 25 | "name": "Y", 26 | "width": 1920, 27 | "height": 1080, 28 | "bit_depth": 10 29 | }, 30 | { 31 | "name": "Cb", 32 | "width": 960, 33 | "height": 1080, 34 | "bit_depth": 10 35 | }, 36 | { 37 | "name": "Cr", 38 | "width": 960, 39 | "height": 1080, 40 | "bit_depth": 10 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/Provider.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include "mxl/fabrics.h" 10 | 11 | namespace mxl::lib::fabrics::ofi 12 | { 13 | 14 | /** \brief Internal representation of supported libfabric providers. 15 | */ 16 | enum class Provider 17 | { 18 | TCP, 19 | VERBS, 20 | EFA, 21 | SHM, 22 | }; 23 | 24 | /** \brief Convert between external and internal versions of this type 25 | */ 26 | mxlFabricsProvider providerToAPI(Provider provider) noexcept; 27 | 28 | /** \brief Convert between external and internal versions of this type 29 | */ 30 | std::optional providerFromAPI(mxlFabricsProvider api) noexcept; 31 | 32 | /** \brief Parse a provider name string, and return the enum value. 33 | * 34 | * Returns std::nullopt if the string passed was not a valid provider name. 35 | */ 36 | std::optional providerFromString(std::string const& s) noexcept; 37 | } 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /lib/tests/data/v210a_flow.json: -------------------------------------------------------------------------------- 1 | { 2 | "$copyright": "SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project.", 3 | "$license": "SPDX-License-Identifier: Apache-2.0", 4 | "description": "MXL Test Flow, 1080p29 with alpha", 5 | "id": "5fbec3b1-1b0f-417d-9059-8b94a47197ed", 6 | "tags": { 7 | "urn:x-nmos:tag:grouphint/v1.0": [ 8 | "Media Function XYZ:Video" 9 | ] 10 | }, 11 | "format": "urn:x-nmos:format:video", 12 | "label": "MXL Test Flow, 1080p29 with alpha", 13 | "parents": [], 14 | "media_type": "video/v210a", 15 | "grain_rate": { 16 | "numerator": 30000, 17 | "denominator": 1001 18 | }, 19 | "frame_width": 1920, 20 | "frame_height": 1080, 21 | "interlace_mode": "progressive", 22 | "colorspace": "BT709", 23 | "components": [ 24 | { 25 | "name": "Y", 26 | "width": 1920, 27 | "height": 1080, 28 | "bit_depth": 10 29 | }, 30 | { 31 | "name": "Cb", 32 | "width": 960, 33 | "height": 1080, 34 | "bit_depth": 10 35 | }, 36 | { 37 | "name": "Cr", 38 | "width": 960, 39 | "height": 1080, 40 | "bit_depth": 10 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.yml: -------------------------------------------------------------------------------- 1 | name: Feature 2 | description: Feature from MXL Requirement 3 | labels: [] 4 | assignees: [] 5 | title: "[Feature] " 6 | 7 | body: 8 | - type: input 9 | id: requirement_link 10 | attributes: 11 | label: Requirement Link 12 | description: Link to the related issue in MXL Requirements repo (e.g., `dmf-mxl/mxl-requirements#99999` or full URL) 13 | placeholder: "dmf-mxl/mxl-requirements#99999" 14 | validations: 15 | required: true 16 | 17 | - type: textarea 18 | id: description 19 | attributes: 20 | label: Description 21 | description: A clear and concise description of the feature 22 | placeholder: "Describe the feature" 23 | validations: 24 | required: true 25 | 26 | - type: textarea 27 | id: additional_context 28 | attributes: 29 | label: Additional context 30 | description: Add any other context or screenshots about the feature request here. 31 | placeholder: "Include any relevant background, links, or images." 32 | validations: 33 | required: false 34 | 35 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 36 | # SPDX-License-Identifier: Apache-2.0 37 | 38 | -------------------------------------------------------------------------------- /lib/tests/fabrics/ofi/test_Address.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include "Address.hpp" 7 | 8 | using namespace mxl::lib::fabrics::ofi; 9 | 10 | TEST_CASE("FabricAddress default construction", "[FabricAddress]") 11 | { 12 | FabricAddress empty; 13 | REQUIRE(empty.size() == 0); 14 | REQUIRE(empty.raw() == nullptr); 15 | REQUIRE(empty.raw() == static_cast(nullptr)); 16 | REQUIRE(empty.toBase64().empty()); 17 | } 18 | 19 | TEST_CASE("FabricAddress base64 decode", "[FabricAddress]") 20 | { 21 | FabricAddress addr = FabricAddress::fromBase64("AQIDBAU="); // base64 for {1,2,3,4,5} 22 | auto* addrInner = static_cast(addr.raw()); 23 | 24 | REQUIRE(addr.size() == 5); 25 | 26 | // Simulate a FabricAddress with some data 27 | std::vector expected = {1, 2, 3, 4, 5}; 28 | for (size_t i = 0; i < addr.size(); i++) 29 | { 30 | REQUIRE(addrInner[i] == expected[i]); 31 | } 32 | 33 | // Encode again and validate we get the same string 34 | std::string b64 = addr.toBase64(); 35 | REQUIRE(b64 == "AQIDBAU="); 36 | } 37 | -------------------------------------------------------------------------------- /rust/mxl/src/grain/data.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub struct GrainData<'a> { 5 | /// The grain payload. This may be a partial payload if the grain is not complete. 6 | /// The length of this slice is given by `commitedSize` in `mxlGrainInfo`. 7 | pub payload: &'a [u8], 8 | 9 | /// The total size of the grain payload, which may be larger than `payload.len()` if the grain is partial. 10 | pub total_size: usize, 11 | } 12 | 13 | impl<'a> GrainData<'a> { 14 | pub fn to_owned(&self) -> OwnedGrainData { 15 | self.into() 16 | } 17 | } 18 | 19 | impl<'a> AsRef> for GrainData<'a> { 20 | fn as_ref(&self) -> &GrainData<'a> { 21 | self 22 | } 23 | } 24 | 25 | pub struct OwnedGrainData { 26 | pub payload: Vec, 27 | } 28 | 29 | impl<'a> From<&GrainData<'a>> for OwnedGrainData { 30 | fn from(value: &GrainData<'a>) -> Self { 31 | Self { 32 | payload: value.payload.to_vec(), 33 | } 34 | } 35 | } 36 | 37 | impl<'a> From> for OwnedGrainData { 38 | fn from(value: GrainData<'a>) -> Self { 39 | value.as_ref().into() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/RemoteRegion.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "RemoteRegion.hpp" 6 | #include 7 | 8 | namespace mxl::lib::fabrics::ofi 9 | { 10 | 11 | ::fi_rma_iov RemoteRegion::toRmaIov() const noexcept 12 | { 13 | return ::fi_rma_iov{.addr = addr, .len = len, .key = rkey}; 14 | } 15 | 16 | bool RemoteRegion::operator==(RemoteRegion const& other) const noexcept 17 | { 18 | return addr == other.addr && len == other.len && rkey == other.rkey; 19 | } 20 | 21 | ::fi_rma_iov const* RemoteRegionGroup::asRmaIovs() const noexcept 22 | { 23 | return _rmaIovs.data(); 24 | } 25 | 26 | bool RemoteRegionGroup::operator==(RemoteRegionGroup const& other) const noexcept 27 | { 28 | return _inner == other._inner; 29 | } 30 | 31 | std::vector<::fi_rma_iov> RemoteRegionGroup::rmaIovsFromGroup(std::vector group) noexcept 32 | { 33 | std::vector<::fi_rma_iov> rmaIovs; 34 | std::ranges::transform(group, std::back_inserter(rmaIovs), [](RemoteRegion const& reg) { return reg.toRmaIov(); }); 35 | return rmaIovs; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/Exception.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "Exception.hpp" 6 | #include 7 | #include "mxl/mxl.h" 8 | 9 | namespace mxl::lib::fabrics::ofi 10 | { 11 | Exception::Exception(std::string msg, mxlStatus status) 12 | : _msg(std::move(msg)) 13 | , _status(status) 14 | {} 15 | 16 | mxlStatus Exception::status() const noexcept 17 | { 18 | return _status; 19 | } 20 | 21 | char const* Exception::what() const noexcept 22 | { 23 | return _msg.c_str(); 24 | } 25 | 26 | FabricException::FabricException(std::string msg, mxlStatus status, int fiErrno) 27 | : Exception(std::move(msg), status) 28 | , _fiErrno(fiErrno) 29 | {} 30 | 31 | int FabricException::fiErrno() const noexcept 32 | { 33 | return _fiErrno; 34 | } 35 | 36 | mxlStatus mxlStatusFromFiErrno(int fiErrno) 37 | { 38 | switch (fiErrno) 39 | { 40 | case -FI_EINTR: return MXL_ERR_INTERRUPTED; 41 | case -FI_EAGAIN: return MXL_ERR_NOT_READY; 42 | default: return MXL_ERR_UNKNOWN; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/ContinuousFlowWriter.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include "FlowWriter.hpp" 7 | 8 | namespace mxl::lib 9 | { 10 | class MXL_EXPORT ContinuousFlowWriter : public FlowWriter 11 | { 12 | public: 13 | /** 14 | * Accessor for a specific set of mutable samples across all 15 | * channels ending at a specific index (`count` samples up to 16 | * `index`). 17 | * 18 | * \param[in] index The starting index of the samples to obtain. 19 | * \param[in] count The number of samples to obtain. 20 | * \param[out] payloadBuffersSlices A reference to a mutable 21 | * wrapped multi buffer slice that represents the requested 22 | * range across all channel buffers 23 | * 24 | * \return A status code describing the outcome of the call. 25 | */ 26 | virtual mxlStatus openSamples(std::uint64_t index, std::size_t count, mxlMutableWrappedMultiBufferSlice& payloadBufferSlices) = 0; 27 | 28 | virtual mxlStatus commit() = 0; 29 | 30 | virtual mxlStatus cancel() = 0; 31 | 32 | protected: 33 | using FlowWriter::FlowWriter; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/LocalRegion.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "LocalRegion.hpp" 6 | #include 7 | 8 | namespace mxl::lib::fabrics::ofi 9 | { 10 | ::iovec LocalRegion::toIovec() const noexcept 11 | { 12 | return ::iovec{.iov_base = reinterpret_cast(addr), .iov_len = len}; 13 | } 14 | 15 | ::iovec const* LocalRegionGroup::asIovec() const noexcept 16 | { 17 | return _iovs.data(); 18 | } 19 | 20 | void* const* LocalRegionGroup::desc() const noexcept 21 | { 22 | return _descs.data(); 23 | } 24 | 25 | std::vector<::iovec> LocalRegionGroup::iovFromGroup(std::vector group) noexcept 26 | { 27 | std::vector<::iovec> iovs; 28 | std::ranges::transform(group, std::back_inserter(iovs), [](LocalRegion const& reg) { return reg.toIovec(); }); 29 | return iovs; 30 | } 31 | 32 | std::vector LocalRegionGroup::descFromGroup(std::vector group) noexcept 33 | { 34 | std::vector descs; 35 | std::ranges::transform(group, std::back_inserter(descs), [](LocalRegion& reg) { return reg.desc; }); 36 | return descs; 37 | } 38 | } // namespace mxl::lib::fabrics::ofi 39 | -------------------------------------------------------------------------------- /utils/gst-looping-filesrc/gst-looping-filesrc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | G_BEGIN_DECLS 26 | 27 | #define GST_TYPE_LOOPING_FILESRC (gst_looping_filesrc_get_type()) 28 | G_DECLARE_FINAL_TYPE(GstLoopingFileSrc, gst_looping_filesrc, GST, LOOPING_FILESRC, GstBaseSrc) 29 | 30 | struct _GstLoopingFileSrc 31 | { 32 | GstBaseSrc basesrc; 33 | gchar* location; 34 | bool loop; 35 | FILE* file; 36 | guint64 file_size; 37 | }; 38 | 39 | void gst_looping_filesrc_register_static(); 40 | 41 | G_END_DECLS 42 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/detail/ClockHelpers.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include "../Timing.hpp" 8 | 9 | namespace mxl::lib::detail 10 | { 11 | constexpr clockid_t clockToId(Clock clock) noexcept 12 | { 13 | switch (clock) 14 | { 15 | case Clock::Monotonic: 16 | #if defined(CLOCK_MONOTONIC_RAW) 17 | return CLOCK_MONOTONIC_RAW; 18 | #else 19 | return CLOCK_MONOTONIC; 20 | #endif 21 | 22 | #if defined(CLOCK_TAI) 23 | case Clock::TAI: return CLOCK_TAI; 24 | #endif 25 | case Clock::ProcessCPUTime: return CLOCK_PROCESS_CPUTIME_ID; 26 | 27 | case Clock::ThreadCPUTime: return CLOCK_THREAD_CPUTIME_ID; 28 | 29 | default: return CLOCK_REALTIME; 30 | } 31 | } 32 | 33 | constexpr Duration getClockOffset(Clock clock) noexcept 34 | { 35 | [[maybe_unused]] 36 | constexpr auto const ZERO_SECONDS = fromSeconds(0.0); 37 | [[maybe_unused]] 38 | constexpr auto const TAI_LEAP_SECONDS = fromSeconds(37.0); 39 | 40 | switch (clock) 41 | { 42 | #if !defined(CLOCK_TAI) 43 | case Clock::TAI: return TAI_LEAP_SECONDS; 44 | #endif 45 | default: return ZERO_SECONDS; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project https://github.com/dmf-mxl/mxl/contributors.md 2 | // SPDX-License-Identifier: Apache-2.0 3 | { 4 | "configurations": [ 5 | { 6 | "name": "(gdb) Current cmake debug target", 7 | "type": "cppdbg", 8 | "request": "launch", 9 | "program": "${command:cmake.launchTargetPath}", 10 | "args": [ 11 | "-d", 12 | "~/mxl_domain", 13 | "-f", 14 | "5fbec3b1-1b0f-417d-9059-8b94a47197ed" 15 | ], 16 | "stopAtEntry": false, 17 | "cwd": "${fileDirname}", 18 | "environment": [ 19 | { 20 | "name": "MXL_LOG_LEVEL", 21 | "value": "debug" 22 | } 23 | ], 24 | "externalConsole": false, 25 | "MIMode": "gdb", 26 | "setupCommands": [ 27 | { 28 | "description": "Enable pretty-printing for gdb", 29 | "text": "-enable-pretty-printing", 30 | "ignoreFailures": true 31 | }, 32 | { 33 | "description": "Set Disassembly Flavor to Intel", 34 | "text": "-gdb-set disassembly-flavor intel", 35 | "ignoreFailures": true 36 | } 37 | ] 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /lib/fabrics/ofi/cmake/mxl-fabrics-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | # Include PkgConfig as a dependency, because we need it to check for 4 | # transitive dependencies 5 | include(CMakeFindDependencyMacro) 6 | find_dependency(PkgConfig) 7 | 8 | # An adaption of CMakeFindDependencyMacro that applies the same logic 9 | # to pkg_check_modules. 10 | # 11 | # This has to be a macro because the call to return is used to end the 12 | # script execution entirely. 13 | macro(find_pkg_config_dependencies prefix) 14 | set(cmake_fpcd_required_arg) 15 | if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED) 16 | set(cmake_fpcd_required_arg REQUIRED) 17 | endif() 18 | 19 | set(cmake_fpcd_quiet_arg) 20 | if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY) 21 | set(cmake_fpcd_quiet_arg QUIET) 22 | endif() 23 | 24 | pkg_check_modules(${prefix} 25 | ${cmake_fpcd_required_arg} ${cmake_fpcd_quiet_arg} IMPORTED_TARGET 26 | ${ARGN} 27 | ) 28 | 29 | set(cmake_fpcd_required_arg) 30 | set(cmake_fpcd_quiet_arg) 31 | 32 | if (NOT ${prefix}_FOUND) 33 | set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "${CMAKE_FIND_PACKAGE_NAME} could not be found because at least of the following pkg-config dependencies could not be found: ${ARGN}") 34 | set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False) 35 | return() 36 | endif() 37 | endmacro() 38 | 39 | find_pkg_config_dependencies(libfabric libfabric) 40 | 41 | include("${CMAKE_CURRENT_LIST_DIR}/libmxl-fabrics-targets.cmake") 42 | 43 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/PosixFlowIoFactory.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include "mxl-internal/FlowIoFactory.hpp" 7 | 8 | namespace mxl::lib 9 | { 10 | struct MXL_EXPORT PosixFlowIoFactory : FlowIoFactory 11 | { 12 | /** \see FlowReaderFactory::createDiscreteFlowReader() */ 13 | virtual std::unique_ptr createDiscreteFlowReader(FlowManager const& manager, uuids::uuid const& flowId, 14 | std::unique_ptr&& data) const override; 15 | /** \see FlowReaderFactory::createContinuousFlowReader() */ 16 | virtual std::unique_ptr createContinuousFlowReader(FlowManager const& manager, uuids::uuid const& flowId, 17 | std::unique_ptr&& data) const override; 18 | /** \see FlowWriterFactory::createDiscreteFlowWriter() */ 19 | virtual std::unique_ptr createDiscreteFlowWriter(FlowManager const& manager, uuids::uuid const& flowId, 20 | std::unique_ptr&& data) const override; 21 | /** \see FlowWriterFactory::createContinuousFlowWriter() */ 22 | virtual std::unique_ptr createContinuousFlowWriter(FlowManager const& manager, uuids::uuid const& flowId, 23 | std::unique_ptr&& data) const override; 24 | 25 | ~PosixFlowIoFactory(); 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/RegisteredRegion.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "RegisteredRegion.hpp" 6 | #include "LocalRegion.hpp" 7 | #include "RemoteRegion.hpp" 8 | 9 | namespace mxl::lib::fabrics::ofi 10 | { 11 | 12 | RemoteRegion RegisteredRegion::toRemote(bool useVirtualAddress) const noexcept 13 | { 14 | auto addr = useVirtualAddress ? _region.base : 0; 15 | 16 | return RemoteRegion{.addr = addr, .len = _region.size, .rkey = _mr.rkey()}; 17 | } 18 | 19 | LocalRegion RegisteredRegion::toLocal() const noexcept 20 | { 21 | return LocalRegion{.addr = _region.base, .len = _region.size, .desc = _mr.desc()}; 22 | } 23 | 24 | std::vector toRemote(std::vector const& groups, bool useVirtualAddress) noexcept 25 | { 26 | std::vector remoteGroups; 27 | std::ranges::transform( 28 | groups, std::back_inserter(remoteGroups), [&](RegisteredRegion const& reg) { return reg.toRemote(useVirtualAddress); }); 29 | return remoteGroups; 30 | } 31 | 32 | std::vector toLocal(std::vector const& groups) noexcept 33 | { 34 | std::vector localGroups; 35 | std::ranges::transform(groups, std::back_inserter(localGroups), [](RegisteredRegion const& reg) { return reg.toLocal(); }); 36 | return localGroups; 37 | } 38 | 39 | } // namespace mxl::lib::fabrics::ofi 40 | -------------------------------------------------------------------------------- /lib/tests/fabrics/ofi/test_Provider.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include "Provider.hpp" 7 | 8 | using namespace mxl::lib::fabrics::ofi; 9 | 10 | TEST_CASE("ofi: Provider enum to API conversion", "[ofi][Provider]") 11 | { 12 | REQUIRE(providerToAPI(Provider::TCP) == MXL_SHARING_PROVIDER_TCP); 13 | REQUIRE(providerToAPI(Provider::VERBS) == MXL_SHARING_PROVIDER_VERBS); 14 | REQUIRE(providerToAPI(Provider::EFA) == MXL_SHARING_PROVIDER_EFA); 15 | REQUIRE(providerToAPI(Provider::SHM) == MXL_SHARING_PROVIDER_SHM); 16 | } 17 | 18 | TEST_CASE("ofi: Provider enum from API conversion", "[ofi][Provider]") 19 | { 20 | REQUIRE(providerFromAPI(MXL_SHARING_PROVIDER_TCP) == Provider::TCP); 21 | REQUIRE(providerFromAPI(MXL_SHARING_PROVIDER_VERBS) == Provider::VERBS); 22 | REQUIRE(providerFromAPI(MXL_SHARING_PROVIDER_EFA) == Provider::EFA); 23 | REQUIRE(providerFromAPI(MXL_SHARING_PROVIDER_SHM) == Provider::SHM); 24 | REQUIRE_FALSE(providerFromAPI(static_cast(999)).has_value()); 25 | } 26 | 27 | TEST_CASE("ofi: Provider from string", "[ofi][Provider]") 28 | { 29 | REQUIRE(providerFromString("tcp") == Provider::TCP); 30 | REQUIRE(providerFromString("verbs") == Provider::VERBS); 31 | REQUIRE(providerFromString("efa") == Provider::EFA); 32 | REQUIRE(providerFromString("shm") == Provider::SHM); 33 | 34 | REQUIRE_FALSE(providerFromString("invalid").has_value()); 35 | REQUIRE_FALSE(providerFromString("foo").has_value()); 36 | } 37 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/FlowState.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace mxl::lib 10 | { 11 | /** 12 | * Internal data relevant to the current state of an active flow. 13 | * This data is shared among media functions for inter process communication 14 | * and synchronization. 15 | */ 16 | struct FlowState 17 | { 18 | /** 19 | * The flow data inode. Used to detect if the flow was recreated and 20 | * the current in-memory mapping of the flow has become stale as a 21 | * result. 22 | */ 23 | ino_t inode; 24 | 25 | /** 26 | * 32 bit word used synchronization between a writer and multiple readers. 27 | * This value can be used by futexes. When a FlowWriter commits some 28 | * data (a grain, a slice, etc) it will increment this value and then 29 | * wake all FlowReaders waiting on this memory address. 30 | */ 31 | std::uint32_t syncCounter; 32 | 33 | /** 34 | * Default constructor that value initializes all members. 35 | */ 36 | constexpr FlowState() noexcept; 37 | }; 38 | 39 | /**************************************************************************/ 40 | /* Inline implementatiom. */ 41 | /**************************************************************************/ 42 | 43 | constexpr FlowState::FlowState() noexcept 44 | : inode{} 45 | , syncCounter{} 46 | {} 47 | } 48 | -------------------------------------------------------------------------------- /lib/internal/src/Deferred.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace mxl::lib 9 | { 10 | /** \brief Helper class that is created by a call to \see defer(). 11 | * When a object created from this class goes out of scope, the function passed to defer() is run. 12 | * This class should never be used directly. 13 | */ 14 | template 15 | class Deferred 16 | { 17 | public: 18 | Deferred(Deferred const&) = delete; 19 | Deferred(Deferred&&) = delete; 20 | Deferred& operator=(Deferred const&) = delete; 21 | Deferred& operator=(Deferred&&) = delete; 22 | 23 | /** \brief Calls the deferred function 24 | */ 25 | constexpr ~Deferred() noexcept(std::is_nothrow_invocable_v) 26 | { 27 | _f(); 28 | } 29 | 30 | private: 31 | /** \brief The construtor is private, an can only be called from defer() 32 | */ 33 | constexpr Deferred(F&& f) 34 | : _f(std::forward(f)) 35 | {} 36 | 37 | /** \brief Allow Deferred to be constructed from defer() 38 | */ 39 | template 40 | friend constexpr Deferred defer(N&& f) noexcept; 41 | 42 | private: 43 | F _f; 44 | }; 45 | 46 | template 47 | [[nodiscard("The value returned from defer() must not be discarded. Discarding it calls the function passed to defer() right away.")]] 48 | constexpr Deferred defer(F&& f) noexcept 49 | { 50 | return Deferred{std::forward(f)}; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/Fabric.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include "FabricInfo.hpp" 10 | 11 | namespace mxl::lib::fabrics::ofi 12 | { 13 | 14 | /** \brief RAIII wrapper around a libfabric fabric object (`fid_fabric`). 15 | */ 16 | class Fabric 17 | { 18 | public: 19 | ~Fabric(); 20 | 21 | Fabric(Fabric const&) = delete; 22 | void operator=(Fabric const&) = delete; 23 | 24 | Fabric(Fabric&&) noexcept; 25 | Fabric& operator=(Fabric&&); 26 | 27 | /** \brief Mutable accessor for the underlying raw libfabric fabric object. 28 | */ 29 | [[nodiscard]] 30 | ::fid_fabric* raw() noexcept; 31 | /** \brief Immutable accessor for the underlying raw libfabric fabric object. 32 | */ 33 | [[nodiscard]] 34 | ::fid_fabric const* raw() const noexcept; 35 | 36 | /** \brief Open a fabric object based on the provided FabricInfoView. 37 | * 38 | * \param info The fabric info to use when opening the fabric. 39 | * \return A shared pointer to the opened Fabric object. 40 | */ 41 | static std::shared_ptr open(FabricInfoView info); 42 | 43 | /** \brief Get a view on the libfabric info used to open this fabric. 44 | */ 45 | [[nodiscard]] 46 | FabricInfoView info() const noexcept; 47 | 48 | private: 49 | void close(); 50 | 51 | Fabric(::fid_fabric* raw, FabricInfoView info); 52 | 53 | private: 54 | ::fid_fabric* _raw; 55 | FabricInfo _info; 56 | }; 57 | 58 | } 59 | -------------------------------------------------------------------------------- /lib/tests/fabrics/ofi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | if (NOT TARGET Catch2::Catch2WithMain) 6 | find_package(Catch2 REQUIRED) 7 | endif() 8 | 9 | add_executable(mxl-fabrics-ofi-tests) 10 | 11 | target_compile_features(mxl-fabrics-ofi-tests 12 | PRIVATE 13 | cxx_std_20 14 | ) 15 | 16 | set_target_properties(mxl-fabrics-ofi-tests 17 | PROPERTIES 18 | POSITION_INDEPENDENT_CODE ON 19 | VISIBILITY_INLINES_HIDDEN ON 20 | C_VISIBILITY_PRESET hidden 21 | CXX_VISIBILITY_PRESET hidden 22 | C_EXTENSIONS OFF 23 | CXX_EXTENSIONS OFF 24 | ) 25 | 26 | target_sources(mxl-fabrics-ofi-tests 27 | PRIVATE 28 | test_Address.cpp 29 | test_Domain.cpp 30 | test_Provider.cpp 31 | test_Region.cpp 32 | ) 33 | 34 | target_link_libraries(mxl-fabrics-ofi-tests 35 | PRIVATE 36 | mxl 37 | mxl-internal-headers 38 | mxl-fabrics 39 | mxl-fabrics-objects 40 | Catch2::Catch2WithMain 41 | stduuid 42 | ) 43 | 44 | target_include_directories(mxl-fabrics-ofi-tests 45 | PRIVATE 46 | "${CMAKE_CURRENT_SOURCE_DIR}/../../../fabrics/ofi/src/internal" 47 | ) 48 | 49 | # Enable LTO/IPO on target if enabled and supported 50 | # This is necessary here, because the tests directly link the OBJECTS library 51 | # that has LTO/IPO enabled. 52 | mxl_enable_target_ipo(mxl-fabrics-ofi-tests) 53 | 54 | include(CTest) 55 | include(Catch) 56 | catch_discover_tests(mxl-fabrics-ofi-tests) 57 | 58 | 59 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/Sync.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include "Timing.hpp" 8 | 9 | namespace mxl::lib 10 | { 11 | /** 12 | * Wait until *in_addr changes or timeout expires. 13 | * 14 | * \param in_addr The memory address to monitor. Must refer to a 32 bit value. 15 | * \param in_expected The initial value expected at in_addr 16 | * \param in_deadline Until when to wait. Timepoint is expected to come from Clock::Realtime. 17 | * \return true if value changed, false if timeout expired 18 | */ 19 | template 20 | bool waitUntilChanged(T const* in_addr, T in_expected, Timepoint in_deadline); 21 | 22 | /** 23 | * Wait until *in_addr changes or timeout expires. 24 | * 25 | * \param in_addr The memory address to monitor. Must refer to a 32 bit value. 26 | * \param in_expected The initial value expected at in_addr 27 | * \param in_timeout How long to wait. 28 | * \return true if value changed, false if timeout expired 29 | */ 30 | template 31 | bool waitUntilChanged(T const* in_addr, T in_expected, Duration in_timeout); 32 | 33 | /** 34 | * Wake a single waiter waiting on in_addr 35 | * 36 | * \param in_addr The memory address to signal. Must refer to a 32 bit value. 37 | */ 38 | template 39 | void wakeOne(T const* in_addr); 40 | 41 | /** 42 | * Wake all waiters waiting on in_addr 43 | * 44 | * \param in_addr The memory address to signal. Must refer to a 32 bit value. 45 | */ 46 | template 47 | void wakeAll(T const* in_addr); 48 | } 49 | -------------------------------------------------------------------------------- /lib/internal/src/PosixFlowIoFactory.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl-internal/PosixFlowIoFactory.hpp" 5 | #include "PosixContinuousFlowReader.hpp" 6 | #include "PosixContinuousFlowWriter.hpp" 7 | #include "PosixDiscreteFlowReader.hpp" 8 | #include "PosixDiscreteFlowWriter.hpp" 9 | 10 | namespace mxl::lib 11 | { 12 | PosixFlowIoFactory::~PosixFlowIoFactory() = default; 13 | 14 | std::unique_ptr PosixFlowIoFactory::createDiscreteFlowReader(FlowManager const& manager, uuids::uuid const& flowId, 15 | std::unique_ptr&& data) const 16 | { 17 | return std::make_unique(manager, flowId, std::move(data)); 18 | } 19 | 20 | std::unique_ptr PosixFlowIoFactory::createContinuousFlowReader(FlowManager const& manager, uuids::uuid const& flowId, 21 | std::unique_ptr&& data) const 22 | { 23 | return std::make_unique(manager, flowId, std::move(data)); 24 | } 25 | 26 | std::unique_ptr PosixFlowIoFactory::createDiscreteFlowWriter(FlowManager const& manager, uuids::uuid const& flowId, 27 | std::unique_ptr&& data) const 28 | { 29 | return std::make_unique(manager, flowId, std::move(data)); 30 | } 31 | 32 | std::unique_ptr PosixFlowIoFactory::createContinuousFlowWriter(FlowManager const& manager, uuids::uuid const& flowId, 33 | std::unique_ptr&& data) const 34 | { 35 | return std::make_unique(manager, flowId, std::move(data)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Doxyfile.in: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Doxyfile configuration for generating documentation for C, C++, and .h files 5 | # located in the lib/ and mxlapp/ subdirectories. 6 | 7 | # Project settings 8 | PROJECT_NAME = "MXL : Media eXchange Layer" 9 | PROJECT_BRIEF = "MXL" 10 | OUTPUT_DIRECTORY = docs 11 | OUTPUT_LANGUAGE = English 12 | 13 | # Input settings 14 | INPUT = @CMAKE_CURRENT_SOURCE_DIR@/README.md @CMAKE_CURRENT_SOURCE_DIR@/lib 15 | FILE_PATTERNS = *.c *.cpp *.h *.hpp *.md 16 | RECURSIVE = YES 17 | USE_MDFILE_AS_MAINPAGE = README.md 18 | 19 | # Build settings 20 | EXTRACT_ALL = YES 21 | EXTRACT_PRIVATE = YES 22 | EXTRACT_STATIC = YES 23 | EXTRACT_LOCAL_CLASSES = YES 24 | EXTRACT_LOCAL_METHODS = YES 25 | 26 | # Source browsing settings 27 | SOURCE_BROWSER = YES 28 | INLINE_SOURCES = YES 29 | 30 | # Documentation generation format (HTML enabled by default) 31 | GENERATE_HTML = YES 32 | HTML_OUTPUT = html 33 | 34 | # Optional: Enable LaTeX or other formats as needed 35 | GENERATE_LATEX = NO 36 | GENERATE_XML = NO 37 | GENERATE_MAN = NO 38 | GENERATE_RTF = NO 39 | 40 | # Warnings and diagnostics 41 | WARNINGS = YES 42 | WARN_IF_UNDOCUMENTED = YES 43 | WARN_NO_PARAMDOC = YES 44 | 45 | # Additional options (optional) 46 | SHOW_USED_FILES = YES 47 | SHOW_FILES = YES 48 | SORT_MEMBER_DOCS = YES 49 | SORT_BRIEF_DOCS = YES 50 | SORT_BY_SCOPE_NAME = YES 51 | 52 | GENERATE_TREEVIEW = YES 53 | DISABLE_INDEX = NO 54 | FULL_SIDEBAR = NO 55 | HTML_EXTRA_STYLESHEET = @AWESOME_CSS_DIR@/doxygen-awesome.css 56 | HTML_COLORSTYLE = LIGHT 57 | GENERATE_TODOLIST = YES 58 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/Provider.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "Provider.hpp" 6 | #include 7 | #include 8 | #include "mxl/fabrics.h" 9 | 10 | namespace mxl::lib::fabrics::ofi 11 | { 12 | 13 | static std::map const providerStringMap = { 14 | {"tcp", Provider::TCP }, 15 | {"verbs", Provider::VERBS}, 16 | {"efa", Provider::EFA }, 17 | {"shm", Provider::SHM }, 18 | }; 19 | 20 | mxlFabricsProvider providerToAPI(Provider provider) noexcept 21 | { 22 | switch (provider) 23 | { 24 | case Provider::TCP: return MXL_SHARING_PROVIDER_TCP; 25 | case Provider::VERBS: return MXL_SHARING_PROVIDER_VERBS; 26 | case Provider::EFA: return MXL_SHARING_PROVIDER_EFA; 27 | case Provider::SHM: return MXL_SHARING_PROVIDER_SHM; 28 | } 29 | 30 | return MXL_SHARING_PROVIDER_AUTO; 31 | } 32 | 33 | std::optional providerFromAPI(mxlFabricsProvider api) noexcept 34 | { 35 | switch (api) 36 | { 37 | case MXL_SHARING_PROVIDER_AUTO: 38 | case MXL_SHARING_PROVIDER_TCP: return Provider::TCP; 39 | case MXL_SHARING_PROVIDER_VERBS: return Provider::VERBS; 40 | case MXL_SHARING_PROVIDER_EFA: return Provider::EFA; 41 | case MXL_SHARING_PROVIDER_SHM: return Provider::SHM; 42 | } 43 | 44 | return std::nullopt; 45 | } 46 | 47 | std::optional providerFromString(std::string const& s) noexcept 48 | { 49 | auto it = providerStringMap.find(s); 50 | if (it == providerStringMap.end()) 51 | { 52 | return std::nullopt; 53 | } 54 | 55 | return it->second; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/Thread.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include "Timing.hpp" 7 | 8 | namespace mxl::lib 9 | { 10 | namespace this_thread 11 | { 12 | /** 13 | * Yield the current thread time slice to other runnable threads. 14 | */ 15 | void yield() noexcept; 16 | 17 | /** 18 | * Perform a CPU level yield operation to briefly relieve pressure on shared 19 | * resources, such as the memory bus during busy loops. 20 | */ 21 | void yieldProcessor() noexcept; 22 | 23 | /** 24 | * Sleep for the specified amount of time to pass on the specified clock. 25 | * 26 | * \param[in] duration the amount of time to sleep for, 27 | * \param[in] clock the clock the specified duration refers to. 28 | * \return The remaining time of the originally specified duration that 29 | * was not spent sleeping because the sleep was interrupted for any 30 | * reason. 31 | * 32 | * If the remaining time is non-zero the condition that caused the 33 | * sleep to abort can be obtained by inspecting errno. 34 | */ 35 | Duration sleep(Duration duration, Clock clock = Clock::Realtime) noexcept; 36 | 37 | /** 38 | * Sleep until the specified point in time is reached by the specified 39 | * clock. 40 | * 41 | * \param[in] timepoint the point in time, until which to sleep. 42 | * \param[in] clock the clock the specified point in time refers to. 43 | * \return 0 on success, or an error number if the sleep failed to 44 | * complete for any reason. 45 | */ 46 | int sleepUntil(Timepoint timepoint, Clock clock = Clock::Realtime) noexcept; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/internal/src/PathUtils.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl-internal/PathUtils.hpp" 5 | #include 6 | #include 7 | 8 | namespace mxl::lib 9 | { 10 | MXL_EXPORT 11 | std::filesystem::path makeFlowDirectoryName(std::filesystem::path const& domain, std::string const& uuid) 12 | { 13 | return domain / (uuid + FLOW_DIRECTORY_NAME_SUFFIX); 14 | } 15 | 16 | MXL_EXPORT 17 | std::filesystem::path makeFlowDataFilePath(std::filesystem::path const& flowDirectory) 18 | { 19 | return flowDirectory / FLOW_DATA_FILE_NAME; 20 | } 21 | 22 | MXL_EXPORT 23 | std::filesystem::path makeFlowDescriptorFilePath(std::filesystem::path const& flowDirectory) 24 | { 25 | return flowDirectory / FLOW_DESCRIPTOR_FILE_NAME; 26 | } 27 | 28 | MXL_EXPORT 29 | std::filesystem::path makeFlowAccessFilePath(std::filesystem::path const& flowDirectory) 30 | { 31 | return flowDirectory / FLOW_ACCESS_FILE_NAME; 32 | } 33 | 34 | MXL_EXPORT 35 | std::filesystem::path makeGrainDirectoryName(std::filesystem::path const& flowDirectory) 36 | { 37 | return flowDirectory / GRAIN_DIRECTORY_NAME; 38 | } 39 | 40 | MXL_EXPORT 41 | std::filesystem::path makeGrainDataFilePath(std::filesystem::path const& grainDirectory, unsigned int index) 42 | { 43 | return grainDirectory / fmt::format("{}.{}", GRAIN_DATA_FILE_NAME_STEM, index); 44 | } 45 | 46 | MXL_EXPORT 47 | std::filesystem::path makeChannelDataFilePath(std::filesystem::path const& flowDirectory) 48 | { 49 | return flowDirectory / CHANNEL_DATA_FILE_NAME; 50 | } 51 | 52 | MXL_EXPORT 53 | std::filesystem::path makeDomainOptionsFilePath(std::filesystem::path const& domain) 54 | { 55 | return domain / (DOMAIN_OPTIONS_FILE_NAME); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/internal/src/FlowIoFactory.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl-internal/FlowIoFactory.hpp" 5 | #include "mxl-internal/FlowWriterFactory.hpp" 6 | #include "DynamicPointerCast.hpp" 7 | 8 | namespace mxl::lib 9 | { 10 | FlowIoFactory::FlowIoFactory() = default; 11 | 12 | FlowIoFactory::~FlowIoFactory() = default; 13 | 14 | std::unique_ptr FlowIoFactory::createFlowReader(FlowManager const& manager, uuids::uuid const& flowId, 15 | std::unique_ptr&& data) 16 | { 17 | if (auto discreteData = dynamic_pointer_cast(std::move(data)); discreteData) 18 | { 19 | return this->createDiscreteFlowReader(manager, flowId, std::move(discreteData)); 20 | } 21 | if (auto continuousData = dynamic_pointer_cast(std::move(data)); continuousData) 22 | { 23 | return this->createContinuousFlowReader(manager, flowId, std::move(continuousData)); 24 | } 25 | throw std::runtime_error("Could not create reader, because flow type is not supported."); 26 | } 27 | 28 | std::unique_ptr FlowIoFactory::createFlowWriter(FlowManager const& manager, uuids::uuid const& flowId, 29 | std::unique_ptr&& data) 30 | { 31 | if (auto discreteData = dynamic_pointer_cast(std::move(data)); discreteData) 32 | { 33 | return this->createDiscreteFlowWriter(manager, flowId, std::move(discreteData)); 34 | } 35 | if (auto continuousData = dynamic_pointer_cast(std::move(data)); continuousData) 36 | { 37 | return this->createContinuousFlowWriter(manager, flowId, std::move(continuousData)); 38 | } 39 | throw std::runtime_error("Could not create writer, because flow type is not supported."); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/Flow.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "FlowInfo.hpp" 12 | #include "FlowState.hpp" 13 | 14 | namespace mxl::lib 15 | { 16 | /// The version of the flow data structs in shared memory that we expect and support. 17 | constexpr auto FLOW_DATA_VERSION = 1U; 18 | 19 | /// The version of the grain header structs in shared memory that we expect an support. 20 | constexpr auto GRAIN_HEADER_VERSION = 1U; 21 | 22 | /// 23 | /// Internal Flow structure stored in shared memory 24 | /// The 'info' field is public and will be returned through the mxl C api 25 | /// 26 | struct Flow 27 | { 28 | mxlFlowInfo info; 29 | mxl::lib::FlowState state; 30 | }; 31 | 32 | /// The first 8KiB of a grain are reserved for the mxlGrainInfo structure, including user data. Ample padding is provided 33 | /// between the header and the payload. Payload is page aligned AND AVX512 (64 bytes) aligned. 34 | constexpr auto const MXL_GRAIN_PAYLOAD_OFFSET = std::size_t{8192}; 35 | 36 | struct GrainHeader 37 | { 38 | mxlGrainInfo info; 39 | 40 | std::uint8_t pad[MXL_GRAIN_PAYLOAD_OFFSET - sizeof info]; 41 | }; 42 | 43 | /// 44 | /// Internal Grain structure stored in shared memory 45 | /// The 'info' field of the header is public and will be returned through the mxl C api 46 | /// 47 | /// The total size of a grain is: 48 | /// - payload in host memory : sizeof header + header.info.grainSize 49 | /// - payload in device memory : sizeof header 50 | /// 51 | struct Grain 52 | { 53 | GrainHeader header; 54 | }; 55 | 56 | std::ostream& operator<<(std::ostream& os, Grain const& obj); 57 | 58 | } // namespace mxl::lib 59 | -------------------------------------------------------------------------------- /utils/gst-looping-filesrc/README.md: -------------------------------------------------------------------------------- 1 | 18 | 19 | # gst-looping-filesrc 20 | 21 | Like GStreamer's `filesrc` but rewinds file to the beginning once EOF is reached. 22 | 23 | Please note that this will only work for video containers that support concatenation like MPEG transport layer (`*.ts`). 24 | Remember to update the pipeline for a input file on your computer! 25 | 26 | If you want to loop other containers you either need to seek the whole pipeline or implement the looping logic at the 27 | demuxer-level. The demuxer would need to correctly offset `dts`/`pts` for the repeating segments and rewind the filesrc 28 | to the beginning (or use this implementation that appears as a infinitely big file). The demuxer pulls buffers from 29 | any typ of filesrc. 30 | 31 | ## Building 32 | 33 | ``` 34 | mkdir build 35 | cd build 36 | cmake -DCMAKE_BUILD_TYPE=Release .. 37 | make -j20 38 | ``` 39 | To use the built library must be in `GST_PLUGIN_PATH` or place in `/usr/lib/x86_64-linux-gnu/gstreamer-1.0/` or 40 | `/opt/nvidia/deepstream/deepstream/lib/gst-plugins` (when the latter has been enabled for GStreamer plugins). 41 | Using `sudo make install` will install to `/usr/lib/x86_64-linux-gnu/gstreamer-1.0/`. 42 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile.amazonlinux: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | ARG BASE_IMAGE_VERSION=2023 5 | FROM amazonlinux:${BASE_IMAGE_VERSION} 6 | 7 | # Configure sysctl parameters 8 | RUN echo "vm.swappiness=0" >> /etc/sysctl.conf 9 | 10 | 11 | COPY ./scripts/ /tmp/scripts 12 | 13 | 14 | # Install dependencies 15 | RUN dnf install -y \ 16 | wget \ 17 | zip \ 18 | unzip \ 19 | tar \ 20 | clang \ 21 | clang-tools-extra \ 22 | ca-certificates \ 23 | git \ 24 | git-lfs \ 25 | openssh-clients \ 26 | pkgconf \ 27 | gcc \ 28 | gcc-c++ \ 29 | make \ 30 | gdb \ 31 | nasm \ 32 | doxygen \ 33 | graphviz \ 34 | autoconf \ 35 | automake \ 36 | libtool \ 37 | htop \ 38 | sudo \ 39 | pip \ 40 | ninja-build \ 41 | shadow-utils \ 42 | rpm-build \ 43 | libasan \ 44 | libtsan \ 45 | libubsan \ 46 | gstreamer1-devel \ 47 | gstreamer1-plugins-base-tools \ 48 | gstreamer1-plugins-base-devel \ 49 | gstreamer1-plugins-good \ 50 | gstreamer1-plugins-bad-free \ 51 | bison \ 52 | flex \ 53 | librdmacm-devel \ 54 | && dnf clean all 55 | 56 | RUN pip install --upgrade cmake 57 | 58 | RUN /tmp/scripts/common/libfabric/install.sh 59 | 60 | # Set default user 61 | ARG USERNAME=devcontainer 62 | ARG USER_UID=1000 63 | ARG USER_GID=$USER_UID 64 | 65 | # Create the user 66 | RUN groupadd --gid $USER_GID $USERNAME \ 67 | && useradd --uid $USER_UID --gid $USER_GID -m -s /bin/bash $USERNAME \ 68 | && echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME \ 69 | && chmod 0440 /etc/sudoers.d/$USERNAME 70 | 71 | USER $USERNAME 72 | WORKDIR /home/$USERNAME 73 | 74 | # vcpkg 75 | RUN git clone https://github.com/microsoft/vcpkg \ 76 | && ./vcpkg/bootstrap-vcpkg.sh 77 | 78 | ENV VCPKG_ROOT=/home/$USERNAME/vcpkg 79 | 80 | COPY ./scripts/ /tmp/scripts/ 81 | RUN /tmp/scripts/common/rust/install-rust.sh 82 | -------------------------------------------------------------------------------- /rust/flake.nix: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | { 5 | description = "Flake for MXL dev"; 6 | 7 | inputs = { 8 | nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/*.tar.gz"; 9 | rust-overlay = { 10 | url = "github:oxalica/rust-overlay"; 11 | inputs.nixpkgs.follows = "nixpkgs"; 12 | }; 13 | }; 14 | 15 | outputs = { 16 | self, 17 | nixpkgs, 18 | rust-overlay 19 | }: let 20 | overlays = [ 21 | (import rust-overlay) 22 | (self: super: { 23 | rustStable = super.rust-bin.stable."1.88.0".default; 24 | rustNightly = super.rust-bin.nightly."2025-06-26".default; 25 | }) 26 | ]; 27 | 28 | allSystems = [ 29 | "x86_64-linux" # 64-bit Intel/AMD Linux 30 | "aarch64-linux" # 64-bit ARM Linux 31 | "x86_64-darwin" # 64-bit Intel macOS 32 | "aarch64-darwin" # 64-bit ARM macOS 33 | ]; 34 | 35 | forAllSystems = f: 36 | nixpkgs.lib.genAttrs allSystems (system: 37 | f { 38 | pkgs = import nixpkgs { 39 | inherit overlays system; 40 | }; 41 | } 42 | ); 43 | in { 44 | devShells = forAllSystems ({pkgs}: { 45 | default = pkgs.mkShell { 46 | LIBCLANG_PATH = pkgs.lib.makeLibraryPath [pkgs.llvmPackages_latest.libclang.lib]; 47 | packages = 48 | (with pkgs; [ 49 | rustStable 50 | rust-analyzer 51 | clang 52 | cmake 53 | pkg-config 54 | ]); 55 | }; 56 | } 57 | ); 58 | nightly = forAllSystems ({pkgs}: { 59 | default = pkgs.mkShell { 60 | LIBCLANG_PATH = pkgs.lib.makeLibraryPath [pkgs.llvmPackages_latest.libclang.lib]; 61 | packages = 62 | (with pkgs; [ 63 | rustNightly 64 | rust-analyzer 65 | clang 66 | cmake 67 | pkg-config 68 | ]); 69 | }; 70 | } 71 | ); 72 | }; 73 | } 74 | -------------------------------------------------------------------------------- /tools/mxl-info/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | include(GNUInstallDirs) 5 | include(FetchContent) 6 | 7 | FetchContent_Declare( 8 | simple_uri_parser 9 | GIT_REPOSITORY https://github.com/jholloc/simple-uri-parser.git 10 | GIT_TAG v1.0.0 11 | ) 12 | 13 | FetchContent_MakeAvailable(simple_uri_parser) 14 | add_library(simple_uri_parser INTERFACE) 15 | 16 | target_include_directories(simple_uri_parser 17 | INTERFACE 18 | ${simple_uri_parser_SOURCE_DIR} 19 | ) 20 | 21 | 22 | add_executable(mxl-info) 23 | target_compile_features(mxl-info 24 | PRIVATE 25 | cxx_std_20 26 | ) 27 | set_target_properties(mxl-info 28 | PROPERTIES 29 | POSITION_INDEPENDENT_CODE ON 30 | VISIBILITY_INLINES_HIDDEN ON 31 | C_VISIBILITY_PRESET hidden 32 | CXX_VISIBILITY_PRESET hidden 33 | C_EXTENSIONS OFF 34 | CXX_EXTENSIONS OFF 35 | ) 36 | target_sources(mxl-info 37 | PRIVATE 38 | main.cpp 39 | ) 40 | 41 | 42 | if (NOT TARGET CLI11::CLI11) 43 | find_package(CLI11 CONFIG REQUIRED) 44 | endif () 45 | 46 | if (NOT TARGET stduuid) 47 | find_package(stduuid CONFIG REQUIRED) 48 | endif () 49 | 50 | if (NOT TARGET fmt::fmt) 51 | find_package(fmt CONFIG REQUIRED) 52 | endif() 53 | 54 | target_link_libraries(mxl-info 55 | PRIVATE 56 | simple_uri_parser 57 | stduuid 58 | fmt::fmt 59 | mxl 60 | CLI11::CLI11 61 | ) 62 | 63 | # Not really a fan of having this relative to the binary, we should leave this 64 | # at the default. 65 | set_target_properties(mxl-info 66 | PROPERTIES 67 | INSTALL_RPATH "$ORIGIN/../lib" 68 | ) 69 | 70 | # Install targets 71 | install(TARGETS mxl-info 72 | COMPONENT ${PROJECT_NAME}-tools 73 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 74 | ) 75 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile.almalinux: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | FROM almalinux:10 5 | 6 | COPY ./scripts/ /tmp/scripts 7 | 8 | # Configure sysctl parameters 9 | RUN echo "vm.swappiness=0" >> /etc/sysctl.conf 10 | RUN dnf install -y epel-release 11 | RUN dnf install -y dnf-plugin-config-manager 12 | RUN dnf config-manager --set-enabled crb 13 | 14 | # Install dependencies 15 | RUN dnf install -y \ 16 | wget \ 17 | zip \ 18 | unzip \ 19 | tar \ 20 | clang \ 21 | clang-tools-extra \ 22 | ca-certificates \ 23 | git \ 24 | git-lfs \ 25 | openssh-clients \ 26 | pkgconf \ 27 | gcc \ 28 | gcc-c++ \ 29 | make \ 30 | gdb \ 31 | nasm \ 32 | doxygen \ 33 | graphviz \ 34 | autoconf \ 35 | automake \ 36 | libtool \ 37 | sudo \ 38 | pip \ 39 | ninja-build \ 40 | shadow-utils \ 41 | rpm-build \ 42 | libasan \ 43 | libtsan \ 44 | libubsan \ 45 | gstreamer1-devel \ 46 | gstreamer1-plugins-base-tools \ 47 | gstreamer1-plugins-base-devel \ 48 | gstreamer1-plugins-good \ 49 | gstreamer1-plugins-bad-free \ 50 | bison \ 51 | flex \ 52 | ccache \ 53 | curl \ 54 | librdmacm-devel \ 55 | && dnf clean all 56 | 57 | RUN pip install --upgrade cmake 58 | 59 | RUN /tmp/scripts/common/libfabric/install.sh 60 | 61 | # Set default user 62 | ARG USERNAME=devcontainer 63 | ARG USER_UID=1000 64 | ARG USER_GID=$USER_UID 65 | 66 | # Create the user 67 | RUN groupadd --gid $USER_GID $USERNAME \ 68 | && useradd --uid $USER_UID --gid $USER_GID -m -s /bin/bash $USERNAME \ 69 | && echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME \ 70 | && chmod 0440 /etc/sudoers.d/$USERNAME 71 | 72 | USER $USERNAME 73 | WORKDIR /home/$USERNAME 74 | 75 | # vcpkg 76 | RUN git clone https://github.com/microsoft/vcpkg \ 77 | && ./vcpkg/bootstrap-vcpkg.sh 78 | 79 | ENV VCPKG_ROOT=/home/$USERNAME/vcpkg 80 | 81 | COPY ./scripts/ /tmp/scripts/ 82 | RUN /tmp/scripts/common/rust/install-rust.sh 83 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/RegisteredRegion.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include "Domain.hpp" 10 | #include "LocalRegion.hpp" 11 | #include "MemoryRegion.hpp" 12 | #include "Region.hpp" 13 | #include "RemoteRegion.hpp" 14 | 15 | namespace mxl::lib::fabrics::ofi 16 | { 17 | /** \brief Represent a registered memory region. 18 | */ 19 | class RegisteredRegion 20 | { 21 | public: 22 | explicit RegisteredRegion(MemoryRegion memoryRegion, Region reg) 23 | : _mr(std::move(memoryRegion)) 24 | , _region(std::move(reg)) 25 | {} 26 | 27 | /** \brief Generate a RemoteRegion from this RegisteredRegion. 28 | * 29 | * \param useVirtualAddress If true, the RemoteRegion will use the virtual address. 30 | * If false, the RemoteRegion will use a zero-based address. 31 | * 32 | * \return The generated RemoteRegion. 33 | */ 34 | [[nodiscard]] 35 | RemoteRegion toRemote(bool useVirtualAddress) const noexcept; 36 | 37 | /** \brief Generate a LocalRegion from this RegisteredRegion. 38 | */ 39 | [[nodiscard]] 40 | LocalRegion toLocal() const noexcept; 41 | 42 | private: 43 | MemoryRegion _mr; 44 | Region _region; 45 | }; 46 | 47 | /** Generate a list of RemoteRegions from a list of RegisteredRegions. 48 | * 49 | * \param useVirtualAddress If true, the RemoteRegions will use the virtual addresses. 50 | * If false, the RemoteRegions will use zero-based addresses. 51 | */ 52 | std::vector toRemote(std::vector const& regions, bool useVirtualAddress) noexcept; 53 | 54 | /** Generate a list of LocalRegions from a list of RegisteredRegions. 55 | */ 56 | std::vector toLocal(std::vector const& regions) noexcept; 57 | } 58 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project https://github.com/dmf-mxl/mxl/contributors.md 2 | // SPDX-License-Identifier: Apache-2.0 3 | { 4 | "rust-analyzer.linkedProjects": [ 5 | "rust/Cargo.toml" 6 | ], 7 | "files.associations": { 8 | "array": "cpp", 9 | "atomic": "cpp", 10 | "bit": "cpp", 11 | "*.tcc": "cpp", 12 | "bitset": "cpp", 13 | "cctype": "cpp", 14 | "charconv": "cpp", 15 | "chrono": "cpp", 16 | "clocale": "cpp", 17 | "cmath": "cpp", 18 | "codecvt": "cpp", 19 | "compare": "cpp", 20 | "complex": "cpp", 21 | "concepts": "cpp", 22 | "condition_variable": "cpp", 23 | "csignal": "cpp", 24 | "cstdarg": "cpp", 25 | "cstddef": "cpp", 26 | "cstdint": "cpp", 27 | "cstdio": "cpp", 28 | "cstdlib": "cpp", 29 | "cstring": "cpp", 30 | "ctime": "cpp", 31 | "cwchar": "cpp", 32 | "cwctype": "cpp", 33 | "deque": "cpp", 34 | "map": "cpp", 35 | "set": "cpp", 36 | "string": "cpp", 37 | "unordered_map": "cpp", 38 | "vector": "cpp", 39 | "exception": "cpp", 40 | "algorithm": "cpp", 41 | "functional": "cpp", 42 | "iterator": "cpp", 43 | "memory": "cpp", 44 | "memory_resource": "cpp", 45 | "numeric": "cpp", 46 | "optional": "cpp", 47 | "random": "cpp", 48 | "ratio": "cpp", 49 | "source_location": "cpp", 50 | "string_view": "cpp", 51 | "system_error": "cpp", 52 | "tuple": "cpp", 53 | "type_traits": "cpp", 54 | "utility": "cpp", 55 | "fstream": "cpp", 56 | "initializer_list": "cpp", 57 | "iomanip": "cpp", 58 | "iosfwd": "cpp", 59 | "iostream": "cpp", 60 | "istream": "cpp", 61 | "limits": "cpp", 62 | "mutex": "cpp", 63 | "new": "cpp", 64 | "numbers": "cpp", 65 | "ostream": "cpp", 66 | "semaphore": "cpp", 67 | "span": "cpp", 68 | "sstream": "cpp", 69 | "stdexcept": "cpp", 70 | "stop_token": "cpp", 71 | "streambuf": "cpp", 72 | "thread": "cpp", 73 | "cinttypes": "cpp", 74 | "typeinfo": "cpp", 75 | "variant": "cpp" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/Fabric.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "Fabric.hpp" 6 | #include 7 | #include 8 | #include 9 | #include "Exception.hpp" 10 | #include "FabricInfo.hpp" 11 | 12 | namespace mxl::lib::fabrics::ofi 13 | { 14 | 15 | std::shared_ptr Fabric::open(FabricInfoView info) 16 | { 17 | ::fid_fabric* fid; 18 | 19 | fiCall(::fi_fabric2, "Failed to open fabric", info.raw(), &fid, 0, nullptr); 20 | 21 | // expose the private constructor to std::make_shared inside this function 22 | struct MakeSharedEnabler : public Fabric 23 | { 24 | MakeSharedEnabler(::fid_fabric* raw, FabricInfoView info) 25 | : Fabric(raw, info) 26 | {} 27 | }; 28 | 29 | return std::make_shared(fid, info); 30 | } 31 | 32 | Fabric::Fabric(::fid_fabric* raw, FabricInfoView info) 33 | : _raw(raw) 34 | , _info(info.owned()) 35 | {} 36 | 37 | Fabric::~Fabric() 38 | { 39 | close(); 40 | } 41 | 42 | Fabric::Fabric(Fabric&& other) noexcept 43 | : _raw(other._raw) 44 | , _info(other._info) 45 | { 46 | other._raw = nullptr; 47 | } 48 | 49 | Fabric& Fabric::operator=(Fabric&& other) 50 | { 51 | close(); 52 | 53 | _raw = other._raw; 54 | _info = other._info; 55 | other._raw = nullptr; 56 | 57 | return *this; 58 | } 59 | 60 | ::fid_fabric* Fabric::raw() noexcept 61 | { 62 | return _raw; 63 | } 64 | 65 | ::fid_fabric const* Fabric::raw() const noexcept 66 | { 67 | return _raw; 68 | } 69 | 70 | FabricInfoView Fabric::info() const noexcept 71 | { 72 | return _info.view(); 73 | } 74 | 75 | void Fabric::close() 76 | { 77 | if (_raw != nullptr) 78 | { 79 | fiCall(::fi_close, "failed to close fabric", &_raw->fid); 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /.devcontainer/amazonlinux/devcontainer.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | { 4 | "name": "mxl - Amazon Linux", 5 | "build": { 6 | "dockerfile": "../Dockerfile.amazonlinux", 7 | "context": "../", 8 | "args": { 9 | "BASE_IMAGE_VERSION": "2023" 10 | } 11 | }, 12 | "runArgs": [ 13 | "--security-opt", 14 | "apparmor:unconfined" 15 | ], 16 | "mounts": [ 17 | // These 2 mount points are required for GUI applications to work in WSL2. Remove them if you are not using WSL2. 18 | "source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached", 19 | "source=/mnt/wslg,target=/mnt/wslg,type=bind,consistency=cached" 20 | ], 21 | "customizations": { 22 | "vscode": { 23 | "extensions": [ 24 | "ms-vscode.cpptools-extension-pack", 25 | "mhutchie.git-graph", 26 | "matepek.vscode-catch2-test-adapter", 27 | "llvm-vs-code-extensions.vscode-clangd", 28 | "xaver.clang-format", 29 | "bierner.markdown-mermaid", 30 | "rust-lang.rust-analyzer" 31 | ], 32 | "settings": { 33 | "C_Cpp.intelliSenseEngine": "disabled", 34 | "editor.inlayHints.enabled": "off", 35 | "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", 36 | "editor.formatOnSave": true, 37 | "[cpp]": { 38 | "editor.defaultFormatter": "xaver.clang-format" 39 | }, 40 | "rust-analyzer.linkedProjects": [ 41 | "${workspaceFolder}/rust/Cargo.toml" 42 | ] 43 | } 44 | } 45 | }, 46 | "containerEnv": { 47 | "NINJA_STATUS": "[%r processes, %f/%t @ %o/s : %es] ", 48 | "CCACHE_DIR": "${containerWorkspaceFolder}/.cache/ccache", 49 | "DISPLAY": "${localEnv:DISPLAY}" 50 | }, 51 | "remoteUser": "devcontainer" 52 | } 53 | -------------------------------------------------------------------------------- /rust/mxl/src/error.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub type Result = core::result::Result; 5 | 6 | #[derive(Debug, thiserror::Error)] 7 | pub enum Error { 8 | #[error("Unknown error: {0}")] 9 | Unknown(mxl_sys::Status), 10 | #[error("Flow not found")] 11 | FlowNotFound, 12 | #[error("Out of range - too late")] 13 | OutOfRangeTooLate, 14 | #[error("Out of range - too early")] 15 | OutOfRangeTooEarly, 16 | #[error("Invalid flow reader")] 17 | InvalidFlowReader, 18 | #[error("Invalid flow writer")] 19 | InvalidFlowWriter, 20 | #[error("Timeout")] 21 | Timeout, 22 | #[error("Invalid argument")] 23 | InvalidArg, 24 | #[error("Conflict")] 25 | Conflict, 26 | /// The error is not defined in the MXL API, but it is used to wrap other errors. 27 | #[error("Other error: {0}")] 28 | Other(String), 29 | 30 | #[error("Null string: {0}")] 31 | NulString(#[from] std::ffi::NulError), 32 | 33 | #[error("Loading library: {0}")] 34 | LibLoading(#[from] libloading::Error), 35 | } 36 | 37 | impl Error { 38 | pub fn from_status(status: mxl_sys::Status) -> Result<()> { 39 | match status { 40 | mxl_sys::MXL_STATUS_OK => Ok(()), 41 | mxl_sys::MXL_ERR_UNKNOWN => Err(Error::Unknown(mxl_sys::MXL_ERR_UNKNOWN)), 42 | mxl_sys::MXL_ERR_FLOW_NOT_FOUND => Err(Error::FlowNotFound), 43 | mxl_sys::MXL_ERR_OUT_OF_RANGE_TOO_LATE => Err(Error::OutOfRangeTooLate), 44 | mxl_sys::MXL_ERR_OUT_OF_RANGE_TOO_EARLY => Err(Error::OutOfRangeTooEarly), 45 | mxl_sys::MXL_ERR_INVALID_FLOW_READER => Err(Error::InvalidFlowReader), 46 | mxl_sys::MXL_ERR_INVALID_FLOW_WRITER => Err(Error::InvalidFlowWriter), 47 | mxl_sys::MXL_ERR_TIMEOUT => Err(Error::Timeout), 48 | mxl_sys::MXL_ERR_INVALID_ARG => Err(Error::InvalidArg), 49 | mxl_sys::MXL_ERR_CONFLICT => Err(Error::Conflict), 50 | other => Err(Error::Unknown(other)), 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /.devcontainer/almalinux/devcontainer.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | { 4 | "name": "mxl - Alma Linux", 5 | "build": { 6 | "dockerfile": "../Dockerfile.almalinux", 7 | "context": "../", 8 | "args": {} 9 | }, 10 | "runArgs": [ 11 | "--security-opt", 12 | "apparmor:unconfined" 13 | ], 14 | "mounts": [ 15 | // These 2 mount points are required for GUI applications to work in WSL2. Remove them if you are not using WSL2. 16 | "source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached", 17 | "source=/mnt/wslg,target=/mnt/wslg,type=bind,consistency=cached" 18 | ], 19 | "customizations": { 20 | "vscode": { 21 | "extensions": [ 22 | "ms-vscode.cpptools-extension-pack", 23 | "mhutchie.git-graph", 24 | "matepek.vscode-catch2-test-adapter", 25 | "llvm-vs-code-extensions.vscode-clangd", 26 | "xaver.clang-format", 27 | "bierner.markdown-mermaid", 28 | "rust-lang.rust-analyzer" 29 | ], 30 | "settings": { 31 | "C_Cpp.intelliSenseEngine": "disabled", 32 | "editor.inlayHints.enabled": "off", 33 | "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", 34 | "editor.formatOnSave": true, 35 | "[cpp]": { 36 | "editor.defaultFormatter": "xaver.clang-format" 37 | }, 38 | "rust-analyzer.linkedProjects": [ 39 | "${workspaceFolder}/rust/Cargo.toml" 40 | ] 41 | } 42 | } 43 | }, 44 | "containerEnv": { 45 | "NINJA_STATUS": "[%r processes, %f/%t @ %o/s : %es] ", 46 | "CCACHE_DIR": "${containerWorkspaceFolder}/.cache/ccache", 47 | "DISPLAY": "${localEnv:DISPLAY}" 48 | }, 49 | "hostRequirements": { 50 | "gpu": "optional" 51 | }, 52 | "remoteUser": "devcontainer" 53 | } 54 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/Address.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace mxl::lib::fabrics::ofi 14 | { 15 | /** 16 | * \brief Wrapper around a libfabric endpoint address. 17 | */ 18 | class FabricAddress final 19 | { 20 | public: 21 | /** 22 | * \brief Default is an empty fabric address 23 | */ 24 | FabricAddress() = default; 25 | 26 | /** 27 | * \brief Retrieve the fabric address of an endpoint by passing its fid. 28 | */ 29 | static FabricAddress fromFid(::fid_t fid); 30 | 31 | /** 32 | * \brief Convert the raw fabric address into a base64 encoded string. 33 | */ 34 | [[nodiscard]] 35 | std::string toBase64() const; 36 | 37 | /** 38 | * \brief Parse a fabric address from a base64 encoded string 39 | */ 40 | static FabricAddress fromBase64(std::string_view data); 41 | 42 | /** 43 | * \brief Pointer to the raw address data. 44 | */ 45 | void* raw() noexcept; 46 | 47 | /** 48 | * \brief Pointer to the raw address data. 49 | */ 50 | [[nodiscard]] 51 | void const* raw() const noexcept; 52 | 53 | /** 54 | * \brief Byte-length of the raw address data. 55 | */ 56 | [[nodiscard]] 57 | std::size_t size() const noexcept; 58 | 59 | bool operator==(FabricAddress const& other) const noexcept; 60 | 61 | private: 62 | explicit FabricAddress(std::vector addr); 63 | 64 | /** \brief Retrieve the fabric address of an endpoint by using its fid. 65 | */ 66 | static FabricAddress retrieveFabricAddress(::fid_t); 67 | 68 | private: 69 | std::vector _inner; /**< libfabric address represented as a buffer of bytes */ 70 | }; 71 | 72 | } 73 | -------------------------------------------------------------------------------- /.devcontainer/debiantrixie/devcontainer.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | { 4 | "name": "mxl - Debian Trixie", 5 | "build": { 6 | "dockerfile": "../Dockerfile.debiantrixie", 7 | "context": "../", 8 | "args": {} 9 | }, 10 | "runArgs": [ 11 | "--security-opt", 12 | "apparmor:unconfined" 13 | ], 14 | "mounts": [ 15 | // These 2 mount points are required for GUI applications to work in WSL2. Remove them if you are not using WSL2. 16 | "source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached", 17 | "source=/mnt/wslg,target=/mnt/wslg,type=bind,consistency=cached" 18 | ], 19 | "customizations": { 20 | "vscode": { 21 | "extensions": [ 22 | "ms-vscode.cpptools-extension-pack", 23 | "mhutchie.git-graph", 24 | "matepek.vscode-catch2-test-adapter", 25 | "llvm-vs-code-extensions.vscode-clangd", 26 | "xaver.clang-format", 27 | "bierner.markdown-mermaid", 28 | "rust-lang.rust-analyzer" 29 | ], 30 | "settings": { 31 | "C_Cpp.intelliSenseEngine": "disabled", 32 | "editor.inlayHints.enabled": "off", 33 | "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", 34 | "editor.formatOnSave": true, 35 | "[cpp]": { 36 | "editor.defaultFormatter": "xaver.clang-format" 37 | }, 38 | "rust-analyzer.linkedProjects": [ 39 | "${workspaceFolder}/rust/Cargo.toml" 40 | ] 41 | } 42 | } 43 | }, 44 | "containerEnv": { 45 | "NINJA_STATUS": "[%r processes, %f/%t @ %o/s : %es] ", 46 | "CCACHE_DIR": "${containerWorkspaceFolder}/.cache/ccache", 47 | "DISPLAY": "${localEnv:DISPLAY}" 48 | }, 49 | "hostRequirements": { 50 | "gpu": "optional" 51 | }, 52 | "remoteUser": "devcontainer" 53 | } 54 | -------------------------------------------------------------------------------- /.devcontainer/ubuntu24/devcontainer.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | { 4 | "name": "mxl - Ubuntu 24.04", 5 | "build": { 6 | "dockerfile": "../Dockerfile", 7 | "context": "../", 8 | "args": { 9 | "BASE_IMAGE_VERSION": "24.04" 10 | } 11 | }, 12 | "runArgs": [ 13 | "--security-opt", 14 | "apparmor:unconfined" 15 | ], 16 | "mounts": [ 17 | // These 2 mount points are required for GUI applications to work in WSL2. Remove them if you are not using WSL2. 18 | "source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached", 19 | "source=/mnt/wslg,target=/mnt/wslg,type=bind,consistency=cached" 20 | ], 21 | "customizations": { 22 | "vscode": { 23 | "extensions": [ 24 | "ms-vscode.cpptools-extension-pack", 25 | "mhutchie.git-graph", 26 | "matepek.vscode-catch2-test-adapter", 27 | "llvm-vs-code-extensions.vscode-clangd", 28 | "xaver.clang-format", 29 | "bierner.markdown-mermaid", 30 | "rust-lang.rust-analyzer" 31 | ], 32 | "settings": { 33 | "C_Cpp.intelliSenseEngine": "disabled", 34 | "editor.inlayHints.enabled": "off", 35 | "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", 36 | "editor.formatOnSave": true, 37 | "[cpp]": { 38 | "editor.defaultFormatter": "xaver.clang-format" 39 | }, 40 | "rust-analyzer.linkedProjects": [ 41 | "${workspaceFolder}/rust/Cargo.toml" 42 | ] 43 | } 44 | } 45 | }, 46 | "containerEnv": { 47 | "NINJA_STATUS": "[%r processes, %f/%t @ %o/s : %es] ", 48 | "CCACHE_DIR": "${containerWorkspaceFolder}/.cache/ccache", 49 | "DISPLAY": "${localEnv:DISPLAY}" 50 | }, 51 | "hostRequirements": { 52 | "gpu": "optional" 53 | }, 54 | "remoteUser": "devcontainer" 55 | } 56 | -------------------------------------------------------------------------------- /.devcontainer/ubuntu26/devcontainer.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | { 4 | "name": "mxl - Ubuntu 26.04", 5 | "build": { 6 | "dockerfile": "../Dockerfile", 7 | "context": "../", 8 | "args": { 9 | "BASE_IMAGE_VERSION": "26.04" 10 | } 11 | }, 12 | "runArgs": [ 13 | "--security-opt", 14 | "apparmor:unconfined" 15 | ], 16 | "mounts": [ 17 | // These 2 mount points are required for GUI applications to work in WSL2. Remove them if you are not using WSL2. 18 | "source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached", 19 | "source=/mnt/wslg,target=/mnt/wslg,type=bind,consistency=cached" 20 | ], 21 | "customizations": { 22 | "vscode": { 23 | "extensions": [ 24 | "ms-vscode.cpptools-extension-pack", 25 | "mhutchie.git-graph", 26 | "matepek.vscode-catch2-test-adapter", 27 | "llvm-vs-code-extensions.vscode-clangd", 28 | "xaver.clang-format", 29 | "bierner.markdown-mermaid", 30 | "rust-lang.rust-analyzer" 31 | ], 32 | "settings": { 33 | "C_Cpp.intelliSenseEngine": "disabled", 34 | "editor.inlayHints.enabled": "off", 35 | "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", 36 | "editor.formatOnSave": true, 37 | "[cpp]": { 38 | "editor.defaultFormatter": "xaver.clang-format" 39 | }, 40 | "rust-analyzer.linkedProjects": [ 41 | "${workspaceFolder}/rust/Cargo.toml" 42 | ] 43 | } 44 | } 45 | }, 46 | "containerEnv": { 47 | "NINJA_STATUS": "[%r processes, %f/%t @ %o/s : %es] ", 48 | "CCACHE_DIR": "${containerWorkspaceFolder}/.cache/ccache", 49 | "DISPLAY": "${localEnv:DISPLAY}" 50 | }, 51 | "hostRequirements": { 52 | "gpu": "optional" 53 | }, 54 | "remoteUser": "devcontainer" 55 | } 56 | -------------------------------------------------------------------------------- /.devcontainer/ubuntu20/devcontainer.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | { 4 | "name": "mxl - Ubuntu 20.04", 5 | "build": { 6 | "dockerfile": "../Dockerfile.ubuntu-legacy", 7 | "context": "../", 8 | "args": { 9 | "BASE_IMAGE_VERSION": "20.04" 10 | } 11 | }, 12 | "runArgs": [ 13 | "--security-opt", 14 | "apparmor:unconfined" 15 | ], 16 | "mounts": [ 17 | // These 2 mount points are required for GUI applications to work in WSL2. Remove them if you are not using WSL2. 18 | "source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached", 19 | "source=/mnt/wslg,target=/mnt/wslg,type=bind,consistency=cached" 20 | ], 21 | "customizations": { 22 | "vscode": { 23 | "extensions": [ 24 | "ms-vscode.cpptools-extension-pack", 25 | "mhutchie.git-graph", 26 | "matepek.vscode-catch2-test-adapter", 27 | "llvm-vs-code-extensions.vscode-clangd", 28 | "xaver.clang-format", 29 | "bierner.markdown-mermaid", 30 | "rust-lang.rust-analyzer" 31 | ], 32 | "settings": { 33 | "C_Cpp.intelliSenseEngine": "disabled", 34 | "editor.inlayHints.enabled": "off", 35 | "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", 36 | "editor.formatOnSave": true, 37 | "[cpp]": { 38 | "editor.defaultFormatter": "xaver.clang-format" 39 | }, 40 | "rust-analyzer.linkedProjects": [ 41 | "${workspaceFolder}/rust/Cargo.toml" 42 | ] 43 | } 44 | } 45 | }, 46 | "containerEnv": { 47 | "NINJA_STATUS": "[%r processes, %f/%t @ %o/s : %es] ", 48 | "CCACHE_DIR": "${containerWorkspaceFolder}/.cache/ccache", 49 | "DISPLAY": "${localEnv:DISPLAY}" 50 | }, 51 | "hostRequirements": { 52 | "gpu": "optional" 53 | }, 54 | "remoteUser": "devcontainer" 55 | } 56 | -------------------------------------------------------------------------------- /.devcontainer/ubuntu22/devcontainer.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | { 4 | "name": "mxl - Ubuntu 22.04", 5 | "build": { 6 | "dockerfile": "../Dockerfile.ubuntu-legacy", 7 | "context": "../", 8 | "args": { 9 | "BASE_IMAGE_VERSION": "22.04" 10 | } 11 | }, 12 | "runArgs": [ 13 | "--security-opt", 14 | "apparmor:unconfined" 15 | ], 16 | "mounts": [ 17 | // These 2 mount points are required for GUI applications to work in WSL2. Remove them if you are not using WSL2. 18 | "source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached", 19 | "source=/mnt/wslg,target=/mnt/wslg,type=bind,consistency=cached" 20 | ], 21 | "customizations": { 22 | "vscode": { 23 | "extensions": [ 24 | "ms-vscode.cpptools-extension-pack", 25 | "mhutchie.git-graph", 26 | "matepek.vscode-catch2-test-adapter", 27 | "llvm-vs-code-extensions.vscode-clangd", 28 | "xaver.clang-format", 29 | "bierner.markdown-mermaid", 30 | "rust-lang.rust-analyzer" 31 | ], 32 | "settings": { 33 | "C_Cpp.intelliSenseEngine": "disabled", 34 | "editor.inlayHints.enabled": "off", 35 | "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", 36 | "editor.formatOnSave": true, 37 | "[cpp]": { 38 | "editor.defaultFormatter": "xaver.clang-format" 39 | }, 40 | "rust-analyzer.linkedProjects": [ 41 | "${workspaceFolder}/rust/Cargo.toml" 42 | ] 43 | } 44 | } 45 | }, 46 | "containerEnv": { 47 | "NINJA_STATUS": "[%r processes, %f/%t @ %o/s : %es] ", 48 | "CCACHE_DIR": "${containerWorkspaceFolder}/.cache/ccache", 49 | "DISPLAY": "${localEnv:DISPLAY}" 50 | }, 51 | "hostRequirements": { 52 | "gpu": "optional" 53 | }, 54 | "remoteUser": "devcontainer" 55 | } 56 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/Format.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include "Provider.hpp" 11 | 12 | namespace ofi = mxl::lib::fabrics::ofi; 13 | 14 | template<> 15 | struct fmt::formatter 16 | { 17 | constexpr auto parse(fmt::format_parse_context& ctx) 18 | { 19 | return ctx.begin(); 20 | } 21 | 22 | template 23 | constexpr auto format(mxlFabricsProvider const& provider, Context& ctx) const 24 | { 25 | switch (provider) 26 | { 27 | case MXL_SHARING_PROVIDER_AUTO: return fmt::format_to(ctx.out(), "auto"); 28 | case MXL_SHARING_PROVIDER_TCP: return fmt::format_to(ctx.out(), "tcp"); 29 | case MXL_SHARING_PROVIDER_VERBS: return fmt::format_to(ctx.out(), "verbs"); 30 | case MXL_SHARING_PROVIDER_EFA: return fmt::format_to(ctx.out(), "efa"); 31 | case MXL_SHARING_PROVIDER_SHM: return fmt::format_to(ctx.out(), "shm"); 32 | default: return fmt::format_to(ctx.out(), "unknown"); 33 | } 34 | } 35 | }; 36 | 37 | template<> 38 | struct fmt::formatter 39 | { 40 | constexpr auto parse(fmt::format_parse_context& ctx) 41 | { 42 | return ctx.begin(); 43 | } 44 | 45 | template 46 | constexpr auto format(ofi::Provider const& provider, Context& ctx) const 47 | { 48 | switch (provider) 49 | { 50 | case ofi::Provider::TCP: return fmt::format_to(ctx.out(), "tcp"); 51 | case ofi::Provider::VERBS: return fmt::format_to(ctx.out(), "verbs"); 52 | case ofi::Provider::EFA: return fmt::format_to(ctx.out(), "efa"); 53 | case ofi::Provider::SHM: return fmt::format_to(ctx.out(), "shm"); 54 | default: return fmt::format_to(ctx.out(), "unknown"); 55 | } 56 | } 57 | }; 58 | 59 | namespace mxl::lib::fabrics::ofi 60 | 61 | { 62 | std::string fiProtocolToString(std::uint64_t) noexcept; 63 | } 64 | -------------------------------------------------------------------------------- /lib/tests/fabrics/ofi/test_Region.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include "mxl/fabrics.h" 7 | #include "mxl/flow.h" 8 | #include "Region.hpp" 9 | 10 | using namespace mxl::lib::fabrics::ofi; 11 | 12 | TEST_CASE("ofi: Region constructors", "[ofi][Constructors]") 13 | { 14 | auto hostLoc = Region::Location::host(); 15 | REQUIRE(hostLoc.isHost()); 16 | REQUIRE(hostLoc.id() == 0); 17 | REQUIRE(hostLoc.iface() == FI_HMEM_SYSTEM); 18 | REQUIRE(hostLoc.toString() == "host"); 19 | 20 | auto cudaLoc = Region::Location::cuda(3); 21 | REQUIRE_FALSE(cudaLoc.isHost()); 22 | REQUIRE(cudaLoc.id() == 3); 23 | REQUIRE(cudaLoc.iface() == FI_HMEM_CUDA); 24 | REQUIRE(cudaLoc.toString() == "cuda, id=3"); 25 | } 26 | 27 | TEST_CASE("ofi: RegionGroup view and iovec conversion", "[ofi][RegionGroup]") 28 | { 29 | auto r1 = Region{0x1000, 64, Region::Location::host()}; 30 | auto r2 = Region{0x2000, 128, Region::Location::host()}; 31 | auto group = RegionGroup({r1, r2}); 32 | REQUIRE(group.size() == 2); 33 | 34 | auto const* iovecs = group.asIovec(); 35 | REQUIRE(iovecs[0].iov_base == reinterpret_cast(0x1000)); 36 | REQUIRE(iovecs[0].iov_len == 64); 37 | 38 | REQUIRE(iovecs[1].iov_base == reinterpret_cast(0x2000)); 39 | REQUIRE(iovecs[1].iov_len == 128); 40 | } 41 | 42 | TEST_CASE("ofi: RegionGroups fromGroups and view", "[ofi][RegionGroups]") 43 | { 44 | // clang-format off 45 | auto inputRegions = std::array{ 46 | mxlFabricsMemoryRegion{ 47 | .addr = 0x3000, 48 | .size = 256, 49 | .loc = {.type = MXL_PAYLOAD_LOCATION_HOST_MEMORY, .deviceId = 0}, 50 | }}; 51 | 52 | // clang-format on 53 | 54 | auto mxlRegions = mxlRegionsFromUser(inputRegions.data(), 1); 55 | 56 | REQUIRE(mxlRegions.regions().size() == 1); 57 | 58 | auto const& region = mxlRegions.regions()[0]; 59 | REQUIRE(region.base == 0x3000); 60 | REQUIRE(region.size == 256); 61 | REQUIRE(region.loc.isHost()); 62 | } 63 | -------------------------------------------------------------------------------- /examples/kube-deployment.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | apiVersion: v1 5 | kind: PersistentVolume 6 | metadata: 7 | name: domain-pv 8 | spec: 9 | capacity: 10 | storage: 1Gi 11 | accessModes: 12 | - ReadWriteMany 13 | storageClassName: hostpath 14 | hostPath: 15 | path: /tmp/domain-data 16 | --- 17 | apiVersion: v1 18 | kind: PersistentVolumeClaim 19 | metadata: 20 | name: domain-pvc 21 | spec: 22 | accessModes: 23 | - ReadWriteMany 24 | resources: 25 | requests: 26 | storage: 1Gi 27 | volumeName: domain-pv 28 | --- 29 | apiVersion: apps/v1 30 | kind: Deployment 31 | metadata: 32 | name: writer-media-function 33 | spec: 34 | replicas: 1 35 | selector: 36 | matchLabels: 37 | app: writer-media-function 38 | template: 39 | metadata: 40 | labels: 41 | app: writer-media-function 42 | spec: 43 | containers: 44 | - name: writer-container 45 | image: mxl-writer:latest 46 | imagePullPolicy: IfNotPresent 47 | # If the image is private, configure ImagePullSecrets 48 | volumeMounts: 49 | - name: domain-volume 50 | mountPath: /domain 51 | volumes: 52 | - name: domain-volume 53 | persistentVolumeClaim: 54 | claimName: domain-pvc 55 | restartPolicy: Always 56 | --- 57 | apiVersion: apps/v1 58 | kind: Deployment 59 | metadata: 60 | name: reader-media-function 61 | spec: 62 | replicas: 1 63 | selector: 64 | matchLabels: 65 | app: reader-media-function 66 | template: 67 | metadata: 68 | labels: 69 | app: reader-media-function 70 | spec: 71 | containers: 72 | - name: reader-container 73 | image: mxl-reader:latest 74 | imagePullPolicy: IfNotPresent 75 | tty: true 76 | stdin: true 77 | volumeMounts: 78 | - name: domain-volume 79 | mountPath: /domain 80 | readOnly: true 81 | volumes: 82 | - name: domain-volume 83 | persistentVolumeClaim: 84 | claimName: domain-pvc 85 | restartPolicy: Always 86 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Docker Compose Example 5 | 6 | This example launches two containers simulating two different media functions executing in separate containers. It relies on docker.io and docker-compose-plugin being installed on the host. 7 | 8 | - An init container is pre-run to create the 'mxl' folder in the host /dev/shm 9 | - Writer container: A bind mount maps /dev/shm/mxl from the host to /domain in read-write mode in the writer media function container. The writer process generates a test pattern with burnt in time of day. 10 | - Reader container: A bind mount maps /dev/shm/mxl from the host to /domain in read-only mode in the reader media function. At the moment the reader media function container is idling. To use it you need to exec into it: 11 | 12 | ```bash 13 | docker exec -it examples-reader-media-function-1 /app/mxl-info -d /domain -f 5fbec3b1-1b0f-417d-9059-8b94a47197ed 14 | ``` 15 | 16 | ## Building 17 | 18 | Compile the whole MXL library and tools using the ```Linux-Clang-Release``` preset by invoking ```ninja all``` in the ```build/Linux-Clang-Release``` directory. Then, in the "examples" directory, run: 19 | 20 | ```bash 21 | docker compose build 22 | ``` 23 | 24 | ## Running 25 | 26 | In the "examples" directory run: 27 | 28 | ```bash 29 | docker compose up 30 | ``` 31 | 32 | # Kubernetes Example 33 | 34 | Note: Tested on Docker Desktop Environment which as the correct default storageclass "HostPath" which has a host path provisioner. Therefore its unlikely to work in managed k8s environments without changes 35 | 36 | Follow the same steps above to build the container images and then run this command to deploy the kubernetes resources: 37 | 38 | ```bash 39 | kubectl create -f kube-deployment.yaml 40 | ``` 41 | 42 | To check the pods are running use this command, once both the reader and writer are running, grab the name name of the reader pod: 43 | 44 | ``` bash 45 | kubectl get pod -w 46 | ``` 47 | 48 | Now execute the following command 49 | 50 | ``` bash 51 | kubectl exec -it -- /app/mxl-info -d /domain -f 5fbec3b1-1b0f-417d-9059-8b94a47197ed 52 | ``` 53 | -------------------------------------------------------------------------------- /lib/internal/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Add the test executable 5 | add_executable(mxl-internal-tests) 6 | target_compile_features(mxl-internal-tests 7 | PRIVATE 8 | cxx_std_20 9 | ) 10 | set_target_properties(mxl-internal-tests 11 | PROPERTIES 12 | POSITION_INDEPENDENT_CODE ON 13 | VISIBILITY_INLINES_HIDDEN ON 14 | C_VISIBILITY_PRESET hidden 15 | CXX_VISIBILITY_PRESET hidden 16 | C_EXTENSIONS OFF 17 | CXX_EXTENSIONS OFF 18 | ) 19 | 20 | target_sources(mxl-internal-tests 21 | PRIVATE 22 | test_domainwatcher.cpp 23 | test_flowmanager.cpp 24 | test_options.cpp 25 | test_sharedmem.cpp 26 | ) 27 | 28 | target_link_libraries(mxl-internal-tests 29 | PRIVATE 30 | mxl-common 31 | mxl-internal-headers 32 | ) 33 | 34 | if (NOT TARGET Catch2::Catch2WithMain) 35 | find_package(Catch2 REQUIRED) 36 | endif() 37 | 38 | if (NOT TARGET stduuid) 39 | find_package(stduuid CONFIG REQUIRED) 40 | endif () 41 | 42 | if (NOT TARGET spdlog::spdlog) 43 | find_package(spdlog CONFIG REQUIRED) 44 | endif () 45 | 46 | if (NOT TARGET fmt::fmt) 47 | find_package(fmt CONFIG REQUIRED) 48 | endif() 49 | 50 | if (NOT TARGET picojson::picojson) 51 | find_package(picojson REQUIRED) 52 | endif() 53 | 54 | if (NOT TARGET PcapPlusPlus::Pcap++) 55 | find_package(PcapPlusPlus CONFIG) 56 | endif() 57 | 58 | 59 | target_link_libraries(mxl-internal-tests 60 | PRIVATE 61 | stduuid 62 | spdlog::spdlog 63 | fmt::fmt 64 | picojson::picojson 65 | Catch2::Catch2WithMain 66 | ) 67 | 68 | if (TARGET PcapPlusPlus::Pcap++) 69 | target_link_libraries(mxl-internal-tests 70 | PRIVATE 71 | PcapPlusPlus::Pcap++ 72 | ) 73 | endif() 74 | 75 | # Enable testing using CTest 76 | include(CTest) 77 | include(Catch) 78 | catch_discover_tests(mxl-internal-tests) 79 | 80 | # Copy test files to the build directory 81 | file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/data DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) 82 | -------------------------------------------------------------------------------- /rust/mxl/src/samples/writer.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use std::sync::Arc; 5 | 6 | use crate::{Error, Result, SamplesWriteAccess, instance::InstanceContext}; 7 | 8 | /// MXL Flow Writer for continuous flows (samples-based data like audio) 9 | pub struct SamplesWriter { 10 | context: Arc, 11 | writer: mxl_sys::FlowWriter, 12 | } 13 | 14 | /// The MXL readers and writers are not thread-safe, so we do not implement `Sync` for them, but 15 | /// there is no reason to not implement `Send`. 16 | unsafe impl Send for SamplesWriter {} 17 | 18 | impl SamplesWriter { 19 | pub(crate) fn new(context: Arc, writer: mxl_sys::FlowWriter) -> Self { 20 | Self { context, writer } 21 | } 22 | 23 | pub fn destroy(mut self) -> Result<()> { 24 | self.destroy_inner() 25 | } 26 | 27 | pub fn open_samples<'a>(&'a self, index: u64, count: usize) -> Result> { 28 | let mut buffer_slice: mxl_sys::MutableWrappedMultiBufferSlice = 29 | unsafe { std::mem::zeroed() }; 30 | unsafe { 31 | Error::from_status(self.context.api.flow_writer_open_samples( 32 | self.writer, 33 | index, 34 | count, 35 | &mut buffer_slice, 36 | ))?; 37 | } 38 | Ok(SamplesWriteAccess::new( 39 | self.context.clone(), 40 | self.writer, 41 | buffer_slice, 42 | )) 43 | } 44 | 45 | fn destroy_inner(&mut self) -> Result<()> { 46 | if self.writer.is_null() { 47 | return Err(Error::InvalidArg); 48 | } 49 | 50 | let mut writer = std::ptr::null_mut(); 51 | std::mem::swap(&mut self.writer, &mut writer); 52 | 53 | Error::from_status(unsafe { 54 | self.context 55 | .api 56 | .release_flow_writer(self.context.instance, writer) 57 | }) 58 | } 59 | } 60 | 61 | impl Drop for SamplesWriter { 62 | fn drop(&mut self) { 63 | if !self.writer.is_null() 64 | && let Err(err) = self.destroy_inner() 65 | { 66 | tracing::error!("Failed to release MXL flow writer (continuous): {:?}", err); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /utils/gst-looping-filesrc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | cmake_minimum_required(VERSION 3.22) 18 | 19 | project(gst-looping-filesrc LANGUAGES C CXX) 20 | 21 | include(GNUInstallDirs) 22 | 23 | find_package(PkgConfig) 24 | 25 | pkg_check_modules(GST REQUIRED IMPORTED_TARGET gstreamer-1.0 gstreamer-base-1.0) 26 | 27 | add_library(looping_filesrc SHARED 28 | gst-looping-filesrc.cpp 29 | ) 30 | 31 | if(MSVC) 32 | # Force to always compile with W4 33 | if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") 34 | string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 35 | else() 36 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") 37 | endif() 38 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 39 | target_compile_options(looping_filesrc PRIVATE 40 | -Wall 41 | -Wno-long-long 42 | -pedantic 43 | ) 44 | endif() 45 | 46 | target_include_directories(looping_filesrc PUBLIC 47 | . 48 | ) 49 | 50 | set_target_properties(looping_filesrc PROPERTIES 51 | CXX_STANDARD 17 52 | CXX_EXTENSIONS OFF 53 | ) 54 | 55 | target_link_libraries(looping_filesrc PUBLIC 56 | PkgConfig::GST 57 | ) 58 | 59 | set_target_properties(PROPERTIES PUBLIC_HEADER gst-looping-filesrc.h) 60 | 61 | set(GSTREAMER_PLUGIN_PATH ${CMAKE_INSTALL_LIBDIR}/gstreamer-1.0 CACHE PATH "Where to install the plugin") 62 | message(STATUS "GSTREAMER_PLUGIN_PATH=\"${GSTREAMER_PLUGIN_PATH}\"") 63 | 64 | install( 65 | TARGETS looping_filesrc 66 | DESTINATION ${GSTREAMER_PLUGIN_PATH} 67 | PUBLIC_HEADER 68 | DESTINATION ${GSTREAMER_PLUGIN_PATH}/include) 69 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile.debiantrixie: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | FROM debian:trixie-slim 5 | 6 | ARG DEBIAN_FRONTEND=noninteractive 7 | 8 | RUN echo 'vm.swappiness=0' >> /etc/sysctl.conf 9 | 10 | COPY ./scripts/ /tmp/scripts 11 | 12 | 13 | # Install basic and runtime dependencies 14 | RUN apt-get update \ 15 | && apt-get install -y --no-install-recommends \ 16 | wget \ 17 | curl \ 18 | zip \ 19 | unzip \ 20 | tar \ 21 | lsb-release \ 22 | apt-transport-https \ 23 | ca-certificates \ 24 | git \ 25 | git-lfs \ 26 | openssh-client \ 27 | pkg-config \ 28 | build-essential \ 29 | gdb \ 30 | nasm \ 31 | doxygen \ 32 | graphviz \ 33 | autoconf \ 34 | automake \ 35 | libtool \ 36 | pkg-config \ 37 | bison \ 38 | flex \ 39 | ccache \ 40 | rustup \ 41 | htop \ 42 | librdmacm-dev 43 | 44 | ARG CLANG_VERSION=19 45 | RUN apt-get install -y --no-install-recommends \ 46 | "clang-${CLANG_VERSION}" \ 47 | "clang-tools-${CLANG_VERSION}" \ 48 | "clang-tidy-${CLANG_VERSION}" \ 49 | "clang-format-${CLANG_VERSION}" \ 50 | cmake \ 51 | ninja-build 52 | 53 | # Make the selected clang version the default alternative 54 | RUN /tmp/scripts/debian/register-clang-version.sh "${CLANG_VERSION}" 100 55 | 56 | 57 | RUN apt-get install -y --no-install-recommends \ 58 | libgstreamer1.0-dev \ 59 | libgstreamer-plugins-base1.0-dev \ 60 | gstreamer1.0-plugins-good \ 61 | gstreamer1.0-plugins-bad \ 62 | gstreamer1.0-plugins-ugly \ 63 | gstreamer1.0-x 64 | 65 | # Install libfabric 66 | RUN /tmp/scripts/common/libfabric/install.sh 67 | 68 | # Set default user 69 | ARG USERNAME=devcontainer 70 | ARG USER_UID=1000 71 | ARG USER_GID=${USER_UID} 72 | 73 | # Create the user 74 | RUN groupadd --gid "${USER_GID}" "${USERNAME}" \ 75 | && useradd --uid "${USER_UID}" --gid "${USER_GID}" -m -s /bin/bash "${USERNAME}" \ 76 | && apt-get install -y sudo \ 77 | && printf '%s ALL=(root) NOPASSWD:ALL\n' "${USERNAME}" > "/etc/sudoers.d/${USERNAME}" \ 78 | && chmod 0440 "/etc/sudoers.d/${USERNAME}" 79 | 80 | USER "${USERNAME}" 81 | WORKDIR "/home/${USERNAME}" 82 | 83 | # Install vcpkg 84 | RUN git clone https://github.com/microsoft/vcpkg \ 85 | && ./vcpkg/bootstrap-vcpkg.sh --disableMetrics 86 | 87 | ENV VCPKG_ROOT="/home/${USERNAME}/vcpkg" 88 | 89 | COPY ./scripts/ /tmp/scripts/ 90 | RUN /tmp/scripts/common/rust/install-rust.sh 91 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/Address.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "Address.hpp" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "mxl/mxl.h" 11 | #include "Base64.hpp" 12 | #include "Exception.hpp" 13 | 14 | namespace mxl::lib::fabrics::ofi 15 | { 16 | FabricAddress::FabricAddress(std::vector addr) 17 | : _inner(std::move(addr)) 18 | {} 19 | 20 | FabricAddress FabricAddress::fromFid(::fid_t fid) 21 | { 22 | return retrieveFabricAddress(fid); 23 | } 24 | 25 | std::string FabricAddress::toBase64() const 26 | { 27 | return base64::encode_into(_inner.cbegin(), _inner.cend()); 28 | } 29 | 30 | void* FabricAddress::raw() noexcept 31 | { 32 | return _inner.data(); 33 | } 34 | 35 | void const* FabricAddress::raw() const noexcept 36 | { 37 | return _inner.data(); 38 | } 39 | 40 | std::size_t FabricAddress::size() const noexcept 41 | { 42 | return _inner.size(); 43 | } 44 | 45 | bool FabricAddress::operator==(FabricAddress const& other) const noexcept 46 | { 47 | return _inner == other._inner; 48 | } 49 | 50 | FabricAddress FabricAddress::fromBase64(std::string_view data) 51 | { 52 | return FabricAddress{base64::decode_into>(data)}; 53 | 54 | auto decoded = base64::decode_into>(data); 55 | if (decoded.empty()) 56 | { 57 | throw std::runtime_error("Failed to decode base64 data into FabricAddress."); 58 | } 59 | return FabricAddress{std::move(decoded)}; 60 | } 61 | 62 | FabricAddress FabricAddress::retrieveFabricAddress(::fid_t fid) 63 | { 64 | // First obtain the address length 65 | size_t addrlen = 0; 66 | auto ret = fi_getname(fid, nullptr, &addrlen); 67 | if (ret != -FI_ETOOSMALL) 68 | { 69 | throw FabricException("Failed to get address length from endpoint.", MXL_ERR_UNKNOWN, ret); 70 | } 71 | 72 | // Now that we have the address length, allocate a receiving buffer and call fi_getname again to retrieve the actual address 73 | std::vector addr(addrlen); 74 | fiCall(fi_getname, "Failed to retrieve endpoint's local address.", fid, addr.data(), &addrlen); 75 | 76 | return FabricAddress{addr}; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /lib/tests/test_pkgconfig_c_link.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | set -e 7 | 8 | usage() { 9 | echo "usage: $0 > " >&2 10 | echo " build_dir Path to the CMake build directory." >&2 11 | echo " triplet vcpkg target triplet used for the build." >&2 12 | echo " BUILD_SHARED_LIBS Indicates whether the build uses shared libraries (ON or OFF)." >&2 13 | echo " MXL_LINKER_FLAG Optional compiler linker-selection flag (e.g. -fuse-ld=lld); empty means use default linker." >&2 14 | echo " c_compiler Path to the C compiler executable." >&2 15 | } 16 | 17 | if [ "$#" -ne 5 ]; then 18 | usage 19 | exit 1 20 | fi 21 | 22 | BUILD_DIR="$1" 23 | VCPKG_TRIPLET="$2" 24 | BUILD_SHARED_LIBS="$3" 25 | MXL_LINKER_FLAG="${4#MXL_LINKER_FLAG=}" 26 | C_COMPILER="$5" 27 | 28 | PKGCFG_STATIC= 29 | RPATH_FLAGS= 30 | if [ "$BUILD_SHARED_LIBS" = "OFF" ]; then 31 | PKGCFG_STATIC="--static" 32 | elif [ "$BUILD_SHARED_LIBS" = "ON" ]; then 33 | RPATH_FLAGS="-Wl,-rpath,$BUILD_DIR/lib" 34 | else 35 | usage 36 | exit 2 37 | fi 38 | 39 | export PKG_CONFIG_PATH="$BUILD_DIR/pkgconfig_test:$BUILD_DIR/vcpkg_installed/$VCPKG_TRIPLET/lib/pkgconfig" 40 | 41 | TEST_DIR="$(mktemp -d /tmp/mxl_pkgconfig_test.XXXXXX)" 42 | 43 | ( 44 | set -e 45 | cd $TEST_DIR 46 | 47 | cat > mxl_link_test.c <<'EOF' 48 | #include 49 | #include 50 | #include 51 | int main(void) 52 | { 53 | mxlInstance instance = mxlCreateInstance("./mxl_link_test_domain", NULL); 54 | int rc = !!instance ? EXIT_SUCCESS : EXIT_FAILURE; 55 | mxlDestroyInstance(instance); 56 | return rc; 57 | } 58 | EOF 59 | 60 | if [ "$BUILD_SHARED_LIBS" = "OFF" ]; then 61 | "$C_COMPILER" mxl_link_test.c \ 62 | $MXL_LINKER_FLAG \ 63 | $(pkg-config --cflags --libs $PKGCFG_STATIC libmxl) \ 64 | -L"$BUILD_DIR/lib/internal" \ 65 | -o mxl_link_test 66 | else 67 | "$C_COMPILER" mxl_link_test.c \ 68 | $MXL_LINKER_FLAG \ 69 | $(pkg-config --cflags --libs $PKGCFG_STATIC libmxl) \ 70 | $RPATH_FLAGS \ 71 | -o mxl_link_test 72 | fi 73 | 74 | mkdir mxl_link_test_domain 75 | ./mxl_link_test 76 | ) 77 | 78 | rm -rf $TEST_DIR/mxl_link_test_domain 79 | rm $TEST_DIR/mxl_link_test 80 | rm $TEST_DIR/mxl_link_test.c 81 | rmdir $TEST_DIR 82 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/FlowOptionsParser.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace mxl::lib 13 | { 14 | /** 15 | * Parses flow options and extracts valid attributes. 16 | */ 17 | class MXL_EXPORT FlowOptionsParser 18 | { 19 | public: 20 | FlowOptionsParser() = default; 21 | 22 | /** 23 | * Parses a json of flow options 24 | * 25 | * \param in_flowOptions The flow options 26 | * \throws std::runtime_error on any parse error 27 | */ 28 | FlowOptionsParser(std::string const& in_flowOptions); 29 | 30 | /** 31 | * Accessor for the 'maxCommitBatchSizeHint' field, which expresses the largest expected batch size in samples (for continuous flows) or 32 | * slices (for discrete flows), in which new data is written to this this flow by its producer. For continuous flows, this value must be less 33 | * than half of the buffer length. For discrete flows, this must be greater or equal to 1. 34 | */ 35 | [[nodiscard]] 36 | std::optional getMaxCommitBatchSizeHint() const; 37 | 38 | /** 39 | * Accessor for the 'maxSyncBatchSizeHint' field, which expresses the largest expected batch size in samples (for continuous flows) or slices 40 | * (for discrete flows), at which availability of new data is signaled to waiting consumers. This must be a multiple of the commit batch size 41 | * greater or equal to 1. 42 | */ 43 | [[nodiscard]] 44 | std::optional getMaxSyncBatchSizeHint() const; 45 | 46 | /** 47 | * Generic accessor for json fields. 48 | * 49 | * \param in_field The field name. 50 | * \return The field value if found. 51 | * \throw If the field is not found or T is incompatible 52 | */ 53 | template 54 | [[nodiscard]] 55 | T get(std::string const& field) const; 56 | 57 | private: 58 | /// \see mxlCommonFlowInfo::maxSyncBatchSizeHint 59 | std::optional _maxSyncBatchSizeHint; 60 | /// \see mxlCommonFlowInfo::maxCommitBatchSizeHint 61 | std::optional _maxCommitBatchSizeHint; 62 | /** The parsed flow object. */ 63 | picojson::object _root; 64 | }; 65 | 66 | } 67 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/DiscreteFlowReader.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include "FlowReader.hpp" 7 | 8 | namespace mxl::lib 9 | { 10 | class MXL_EXPORT DiscreteFlowReader : public FlowReader 11 | { 12 | public: 13 | /** 14 | * Accessor for a specific grain at a specific index. 15 | * The index must be greater than or equal to the current tail index of the flow. 16 | * 17 | * \param in_index The grain index. 18 | * \param in_minValidSlices The expected number of valid slices in the returned mxlGrainInfo. 19 | * \param in_timeoutNs How long to wait in nanoseconds for the grain if in_index is > mxlFlowRuntimeInfo.headIndex 20 | * \param out_grainInfo A valid pointer to mxlGrainInfo that will be copied to 21 | * \param out_payload A valid void pointer to pointer that will be set to the first byte of the grain payload. 22 | * Payload size is available in the mxlGrainInfo structure. 23 | * 24 | * \return A status code describing the outcome of the call. Please note 25 | * that this method will never return MXL_ERR_TIMEOUT, because the 26 | * actual error that is being encountered in this case is 27 | * MXL_ERR_OUT_OF_RANGE_TOO_EARLY, even after waiting. 28 | */ 29 | virtual mxlStatus getGrain(std::uint64_t in_index, std::uint16_t in_minValidSlices, std::uint64_t in_timeoutNs, mxlGrainInfo* out_grainInfo, 30 | std::uint8_t** out_payload) = 0; 31 | 32 | /** 33 | * Non-blocking accessor for a specific grain at a specific index. 34 | * The index must be greater than or equal to the current tail index of the flow. 35 | * 36 | * \param in_index The grain index. 37 | * \param in_minValidSlices The expected number of valid slices in the returned mxlGrainInfo. 38 | * \param out_grainInfo A valid pointer to mxlGrainInfo that will be copied to 39 | * \param out_payload A valid void pointer to pointer that will be set to the first byte of the grain payload. 40 | * Payload size is available in the mxlGrainInfo structure. 41 | * 42 | * \return A status code describing the outcome of the call. 43 | */ 44 | virtual mxlStatus getGrain(std::uint64_t in_index, std::uint16_t in_minValidSlices, mxlGrainInfo* out_grainInfo, 45 | std::uint8_t** out_payload) = 0; 46 | 47 | protected: 48 | using FlowReader::FlowReader; 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /lib/src/time.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl/time.h" 5 | #include "mxl-internal/Thread.hpp" 6 | #include "mxl-internal/Timing.hpp" 7 | 8 | extern "C" 9 | MXL_EXPORT 10 | uint64_t mxlGetTime() 11 | { 12 | return currentTime(mxl::lib::Clock::TAI).value; 13 | } 14 | 15 | extern "C" 16 | MXL_EXPORT 17 | uint64_t mxlGetCurrentIndex(mxlRational const* editRate) 18 | { 19 | if ((editRate == nullptr) || (editRate->denominator == 0) || (editRate->numerator == 0)) 20 | { 21 | return MXL_UNDEFINED_INDEX; 22 | } 23 | 24 | auto const now = mxlGetTime(); 25 | return now ? mxlTimestampToIndex(editRate, now) : MXL_UNDEFINED_INDEX; 26 | } 27 | 28 | extern "C" 29 | MXL_EXPORT 30 | uint64_t mxlTimestampToIndex(mxlRational const* editRate, uint64_t timestamp) 31 | { 32 | if ((editRate == nullptr) || (editRate->denominator == 0) || (editRate->numerator == 0)) 33 | { 34 | return MXL_UNDEFINED_INDEX; 35 | } 36 | 37 | return static_cast((timestamp * __int128_t{editRate->numerator} + 500'000'000 * __int128_t{editRate->denominator}) / 38 | (1'000'000'000 * __int128_t{editRate->denominator})); 39 | } 40 | 41 | extern "C" 42 | MXL_EXPORT 43 | uint64_t mxlIndexToTimestamp(mxlRational const* editRate, uint64_t index) 44 | { 45 | // Validate the edit rate 46 | if ((editRate == nullptr) || (editRate->denominator == 0) || (editRate->numerator == 0)) 47 | { 48 | return MXL_UNDEFINED_INDEX; 49 | } 50 | 51 | return static_cast( 52 | (index * __int128_t{editRate->denominator} * 1'000'000'000 + __int128_t{editRate->numerator} / 2) / __int128_t{editRate->numerator}); 53 | } 54 | 55 | extern "C" 56 | MXL_EXPORT 57 | uint64_t mxlGetNsUntilIndex(uint64_t index, mxlRational const* editRate) 58 | { 59 | // Validate the edit rate 60 | if ((editRate == nullptr) || (editRate->denominator == 0) || (editRate->numerator == 0)) 61 | { 62 | return MXL_UNDEFINED_INDEX; 63 | } 64 | 65 | auto const targetNs = mxlIndexToTimestamp(editRate, index); 66 | auto const nowNs = mxlGetTime(); 67 | return ((nowNs != 0ULL) && (targetNs >= nowNs)) ? targetNs - nowNs : 0ULL; 68 | } 69 | 70 | extern "C" 71 | MXL_EXPORT 72 | void mxlSleepForNs(uint64_t ns) 73 | { 74 | mxl::lib::this_thread::sleep(mxl::lib::Duration(ns), mxl::lib::Clock::TAI); 75 | } 76 | 77 | extern "C" 78 | MXL_EXPORT 79 | void mxlSleepUntil(uint64_t timestamp) 80 | { 81 | mxl::lib::this_thread::sleepUntil(mxl::lib::Timepoint(timestamp), mxl::lib::Clock::TAI); 82 | } 83 | -------------------------------------------------------------------------------- /lib/src/mxl.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl/mxl.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "mxl-internal/Instance.hpp" 10 | #include "mxl-internal/Logging.hpp" 11 | #include "mxl-internal/PosixFlowIoFactory.hpp" 12 | 13 | static char const g_mxl_version_string[] = MXL_VERSION_FULL; 14 | 15 | extern "C" 16 | MXL_EXPORT 17 | mxlStatus mxlGetVersion(mxlVersionType* out_version) 18 | { 19 | if (out_version != nullptr) 20 | { 21 | out_version->major = MXL_VERSION_MAJOR; 22 | out_version->minor = MXL_VERSION_MINOR; 23 | out_version->bugfix = MXL_VERSION_PATCH; 24 | out_version->build = MXL_VERSION_BUILD; 25 | out_version->full = g_mxl_version_string; 26 | return MXL_STATUS_OK; 27 | } 28 | else 29 | { 30 | return MXL_ERR_INVALID_ARG; 31 | } 32 | } 33 | 34 | extern "C" MXL_EXPORT 35 | mxlInstance mxlCreateInstance(char const* in_mxlDomain, char const* in_options) 36 | { 37 | try 38 | { 39 | auto const opts = (in_options != nullptr) ? in_options : ""; 40 | auto flowIoFactory = std::make_unique(); 41 | return reinterpret_cast(new mxl::lib::Instance{in_mxlDomain, opts, std::move(flowIoFactory)}); 42 | } 43 | catch (std::exception& e) 44 | { 45 | MXL_ERROR("Failed to create instance : {}", e.what()); 46 | return nullptr; 47 | } 48 | catch (...) 49 | { 50 | MXL_ERROR("Failed to create instance"); 51 | return nullptr; 52 | } 53 | } 54 | 55 | extern "C" 56 | MXL_EXPORT 57 | mxlStatus mxlDestroyInstance(mxlInstance in_instance) 58 | { 59 | try 60 | { 61 | delete mxl::lib::to_Instance(in_instance); 62 | return (in_instance != nullptr) ? MXL_STATUS_OK : MXL_ERR_INVALID_ARG; 63 | } 64 | catch (...) 65 | { 66 | return MXL_ERR_UNKNOWN; 67 | } 68 | } 69 | 70 | extern "C" 71 | MXL_EXPORT 72 | mxlStatus mxlGarbageCollectFlows(mxlInstance in_instance) 73 | { 74 | try 75 | { 76 | if (auto const instance = mxl::lib::to_Instance(in_instance); instance != nullptr) 77 | { 78 | MXL_DEBUG("Starting garbage collection of flows"); 79 | [[maybe_unused]] 80 | auto count = instance->garbageCollect(); 81 | MXL_DEBUG("Garbage collected {} flows", count); 82 | return MXL_STATUS_OK; 83 | } 84 | else 85 | { 86 | return MXL_ERR_INVALID_ARG; 87 | } 88 | } 89 | catch (...) 90 | { 91 | return MXL_ERR_UNKNOWN; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/ContinuousFlowReader.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include "FlowReader.hpp" 7 | 8 | namespace mxl::lib 9 | { 10 | class MXL_EXPORT ContinuousFlowReader : public FlowReader 11 | { 12 | public: 13 | /** 14 | * Accessor for a specific set of samples across all channels 15 | * ending at a specific index (`count` samples up to `index`). 16 | * 17 | * \param[in] index The starting index of the samples to obtain. 18 | * \param[in] count The number of samples to obtain. 19 | * \param[in] timeoutNs How long to wait in nanoseconds for the range 20 | * of samples to become available. 21 | * \param[out] payloadBuffersSlices A reference to a wrapped multi 22 | * buffer slice that represents the requested range across all 23 | * channel buffers 24 | * 25 | * \return A status code describing the outcome of the call. Please note 26 | * that this method will never return MXL_ERR_TIMEOUT, because the 27 | * actual error that is being encountered in this case is 28 | * MXL_ERR_OUT_OF_RANGE_TOO_EARLY, even after waiting. 29 | * \note No guarantees are made as to how long the caller may 30 | * safely hang on to the returned range of samples without the 31 | * risk of these samples being overwritten. 32 | */ 33 | virtual mxlStatus getSamples(std::uint64_t index, std::size_t count, std::uint64_t timeoutNs, 34 | mxlWrappedMultiBufferSlice& payloadBufferSlices) = 0; 35 | 36 | /** 37 | * Non-blocking accessor for a specific set of samples across all 38 | * channels ending at a specific index (`count` samples up to `index`). 39 | * 40 | * \param[in] index The starting index of the samples to obtain. 41 | * \param[in] count The number of samples to obtain. 42 | * \param[out] payloadBuffersSlices A reference to a wrapped multi 43 | * buffer slice that represents the requested range across all 44 | * channel buffers 45 | * 46 | * \return A status code describing the outcome of the call. 47 | * \note No guarantees are made as to how long the caller may 48 | * safely hang on to the returned range of samples without the 49 | * risk of these samples being overwritten. 50 | */ 51 | virtual mxlStatus getSamples(std::uint64_t index, std::size_t count, mxlWrappedMultiBufferSlice& payloadBufferSlices) = 0; 52 | 53 | protected: 54 | using FlowReader::FlowReader; 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | ARG BASE_IMAGE_VERSION=24.04 5 | FROM ubuntu:${BASE_IMAGE_VERSION} 6 | 7 | ARG DEBIAN_FRONTEND=noninteractive 8 | 9 | RUN echo 'vm.swappiness=0' >> /etc/sysctl.conf 10 | 11 | COPY ./scripts/ /tmp/scripts 12 | 13 | # Install basic and runtime dependencies 14 | RUN apt clean all && apt-get update \ 15 | && apt-get install -y --no-install-recommends \ 16 | wget \ 17 | curl \ 18 | zip \ 19 | unzip \ 20 | tar \ 21 | lsb-release \ 22 | apt-transport-https \ 23 | ca-certificates \ 24 | software-properties-common \ 25 | git \ 26 | git-lfs \ 27 | openssh-client \ 28 | pkg-config \ 29 | build-essential \ 30 | gdb \ 31 | nasm \ 32 | doxygen \ 33 | graphviz \ 34 | autoconf \ 35 | automake \ 36 | libtool \ 37 | pkg-config \ 38 | bison \ 39 | flex \ 40 | htop \ 41 | ccache \ 42 | rustup \ 43 | librdmacm-dev 44 | 45 | 46 | ARG CLANG_VERSION=19 47 | RUN apt-get install -y --no-install-recommends \ 48 | "clang-${CLANG_VERSION}" \ 49 | "clang-tools-${CLANG_VERSION}" \ 50 | "clang-tidy-${CLANG_VERSION}" \ 51 | "clang-format-${CLANG_VERSION}" \ 52 | "llvm-${CLANG_VERSION}" \ 53 | cmake \ 54 | ninja-build 55 | 56 | # Make the selected clang version the default alternative 57 | RUN /tmp/scripts/debian/register-clang-version.sh "${CLANG_VERSION}" 100 58 | 59 | RUN apt-get update && apt-get install -y --no-install-recommends \ 60 | libgstreamer1.0-dev \ 61 | libgstreamer-plugins-base1.0-dev \ 62 | gstreamer1.0-plugins-good \ 63 | gstreamer1.0-plugins-bad \ 64 | gstreamer1.0-plugins-ugly \ 65 | gstreamer1.0-x 66 | 67 | RUN /tmp/scripts/common/libfabric/install.sh 68 | 69 | # Remove the default ubuntu user if it exists 70 | RUN userdel --remove ubuntu >/dev/null 2>&1 || true 71 | RUN groupdel ubuntu >/dev/null 2>&1 || true 72 | 73 | # Set default user 74 | ARG USERNAME=devcontainer 75 | ARG USER_UID=1000 76 | ARG USER_GID=${USER_UID} 77 | 78 | # Create the user 79 | RUN groupadd --gid "${USER_GID}" "${USERNAME}" \ 80 | && useradd --uid "${USER_UID}" --gid "${USER_GID}" -m -s /bin/bash "${USERNAME}" \ 81 | && apt-get install -y sudo \ 82 | && printf '%s ALL=(root) NOPASSWD:ALL\n' "${USERNAME}" > "/etc/sudoers.d/${USERNAME}" \ 83 | && chmod 0440 "/etc/sudoers.d/${USERNAME}" 84 | 85 | USER "${USERNAME}" 86 | WORKDIR "/home/${USERNAME}" 87 | 88 | # Install vcpkg 89 | RUN git clone https://github.com/microsoft/vcpkg \ 90 | && ./vcpkg/bootstrap-vcpkg.sh --disableMetrics 91 | 92 | ENV VCPKG_ROOT="/home/${USERNAME}/vcpkg" 93 | 94 | COPY ./scripts/ /tmp/scripts/ 95 | RUN /tmp/scripts/common/rust/install-rust.sh 96 | -------------------------------------------------------------------------------- /rust/mxl/src/samples/data.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use std::marker::PhantomData; 5 | 6 | use crate::Error; 7 | 8 | pub struct SamplesData<'a> { 9 | buffer_slice: mxl_sys::WrappedMultiBufferSlice, 10 | phantom: PhantomData<&'a ()>, 11 | } 12 | 13 | impl<'a> SamplesData<'a> { 14 | pub(crate) fn new(buffer_slice: mxl_sys::WrappedMultiBufferSlice) -> Self { 15 | Self { 16 | buffer_slice, 17 | phantom: Default::default(), 18 | } 19 | } 20 | 21 | pub fn num_of_channels(&self) -> usize { 22 | self.buffer_slice.count 23 | } 24 | 25 | pub fn channel_data(&self, channel: usize) -> crate::Result<(&[u8], &[u8])> { 26 | if channel >= self.buffer_slice.count { 27 | return Err(Error::InvalidArg); 28 | } 29 | unsafe { 30 | let ptr_1 = (self.buffer_slice.base.fragments[0].pointer as *const u8) 31 | .add(self.buffer_slice.stride * channel); 32 | let size_1 = self.buffer_slice.base.fragments[0].size; 33 | let ptr_2 = (self.buffer_slice.base.fragments[1].pointer as *const u8) 34 | .add(self.buffer_slice.stride * channel); 35 | let size_2 = self.buffer_slice.base.fragments[1].size; 36 | Ok(( 37 | std::slice::from_raw_parts(ptr_1, size_1), 38 | std::slice::from_raw_parts(ptr_2, size_2), 39 | )) 40 | } 41 | } 42 | 43 | pub fn to_owned(&self) -> OwnedSamplesData { 44 | self.into() 45 | } 46 | } 47 | 48 | impl<'a> AsRef> for SamplesData<'a> { 49 | fn as_ref(&self) -> &SamplesData<'a> { 50 | self 51 | } 52 | } 53 | 54 | pub struct OwnedSamplesData { 55 | /// Data belonging to each of the channels. 56 | pub payload: Vec>, 57 | } 58 | 59 | impl<'a> From<&SamplesData<'a>> for OwnedSamplesData { 60 | fn from(value: &SamplesData<'a>) -> Self { 61 | let mut payload = Vec::with_capacity(value.buffer_slice.count); 62 | for channel in 0..value.buffer_slice.count { 63 | // The following unwrap is safe because the channel index always stays in the valid range. 64 | let (data_1, data_2) = value.channel_data(channel).unwrap(); 65 | let mut channel_payload = Vec::with_capacity(data_1.len() + data_2.len()); 66 | channel_payload.extend(data_1); 67 | channel_payload.extend(data_2); 68 | payload.push(channel_payload); 69 | } 70 | Self { payload } 71 | } 72 | } 73 | 74 | impl<'a> From> for OwnedSamplesData { 75 | fn from(value: SamplesData<'a>) -> Self { 76 | value.as_ref().into() 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /docs/Addressability.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # MXL Addressability 5 | 6 | The following addressing scheme allows applications to refer to one or multiple flows hosted in an MXL domain on a local host or on a remote server. 7 | 8 | ## URI 9 | 10 | An MXL flow or group of flows can be addressed using this RFC 3986 compatible format: 11 | 12 | ``` 13 | mxl:///?id=&id= 14 | ``` 15 | 16 | 17 | ### Authority (optional) 18 | 19 | 20 | ``` 21 | = [ ":" ] 22 | ``` 23 | 24 | Where: 25 | ``` 26 | = hostname | IPv4 | "[" IPv6 "]" 27 | = decimal integer (optional) 28 | ``` 29 | 30 | Examples: 31 | ``` 32 | mxl://host1.local/domain/path?id=&id= 33 | mxl://10.1.2.3:5000/domain/path?id=&id= 34 | mxl://[2001:db8::2]/domain/path?id=&id= 35 | ``` 36 | 37 | If authority is absent, the syntax becomes: 38 | ``` 39 | mxl:///domain/path?id=&id= 40 | ``` 41 | 42 | ### Domain Path (Required) 43 | 44 | ``` 45 | = "/" *( "/" ) 46 | ``` 47 | 48 | The ```domain-path``` part of the URI is required and refers to the file system path *in the context of the media function* of the MXL domain. The domain path may need to be translated by media functions or orchestration layer(s). For example, an MXL domain may live on ```/dev/shm/domain1``` on a host but is mapped inside a container to ```/dev/shm/mxl```. This translation is outside the scope of the MXL project. 49 | 50 | 51 | 52 | ### Query Component (Optional) 53 | 54 | The query component of an MXL URI is optional. When present, it is used exclusively to specify one or more flow identifiers through the id parameter. 55 | 56 | The general form is: 57 | 58 | ``` 59 | ? 60 | ``` 61 | 62 | 63 | If the query component is absent, no flow selection is implied and the URI simply refers to the root of the MXL domain 64 | 65 | 66 | ## Structure 67 | 68 | ``` 69 | id-param = "id=" uuid 70 | id-parameters = id-param *( "&" id-param ) 71 | ``` 72 | The id name is mandatory for each parameter. 73 | 74 | 75 | Examples: 76 | 77 | ``` 78 | ?id=550e8400-e29b-41d4-a716-446655440000 79 | ?id=11111111-2222-3333-4444-555555555555&id=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee 80 | ``` 81 | 82 | ## UUID Format 83 | 84 | A UUID is defined according to the canonical textual representation in lowercase or uppercase hexadecimal: 85 | 86 | ``` 87 | uuid = 8HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 12HEXDIG 88 | ``` 89 | 90 | Where: 91 | 92 | ``` 93 | HEXDIG = 0–9 or A–F or a–f 94 | ``` 95 | 96 | Hyphens (-) appear only in the fixed canonical positions. No surrounding {} braces are allowed. No URN (urn:uuid:) form is allowed. 97 | -------------------------------------------------------------------------------- /lib/include/mxl/dataformat.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #ifdef __cplusplus 7 | extern "C" 8 | { 9 | #endif 10 | /** 11 | * Source and flow data formats as defined by AMWA NMOS IS-04, excluding `urn:x-nmos:format:data.event`. 12 | */ 13 | typedef enum mxlDataFormat 14 | { 15 | MXL_DATA_FORMAT_UNSPECIFIED, 16 | MXL_DATA_FORMAT_VIDEO, 17 | MXL_DATA_FORMAT_AUDIO, 18 | MXL_DATA_FORMAT_DATA, 19 | } mxlDataFormat; 20 | 21 | /** 22 | * Return whether the specified format is valid. 23 | * \param[in] format the mxlDataFormat of interest. 24 | * \return 1 if the format specified in \p format is valid, otherwise 0. 25 | */ 26 | inline int mxlIsValidDataFormat(int format) 27 | { 28 | switch (format) 29 | { 30 | case MXL_DATA_FORMAT_VIDEO: 31 | case MXL_DATA_FORMAT_AUDIO: 32 | case MXL_DATA_FORMAT_DATA: return 1; 33 | 34 | default: return 0; 35 | } 36 | } 37 | 38 | /** 39 | * Return whether the specified format is supported by MXL. 40 | * \param[in] format the mxlDataFormat of interest. 41 | * \return 1 if the format specified in \p format is supported, otherwise 0. 42 | */ 43 | inline int mxlIsSupportedDataFormat(int format) 44 | { 45 | switch (format) 46 | { 47 | case MXL_DATA_FORMAT_VIDEO: 48 | case MXL_DATA_FORMAT_AUDIO: 49 | case MXL_DATA_FORMAT_DATA: return 1; 50 | 51 | default: return 0; 52 | } 53 | } 54 | 55 | /** 56 | * Return whether the specified format is operating in discrete grains. 57 | * \param[in] format the mxlDataFormat of interest. 58 | * \return 1 if the format specified in \p format is operating with 59 | * continuous samples, otherwise 0. 60 | */ 61 | inline int mxlIsDiscreteDataFormat(int format) 62 | { 63 | switch (format) 64 | { 65 | case MXL_DATA_FORMAT_VIDEO: 66 | case MXL_DATA_FORMAT_DATA: return 1; 67 | 68 | default: return 0; 69 | } 70 | } 71 | 72 | /** 73 | * Return whether the specified format is operating in continuous samples. 74 | * \param[in] format the mxlDataFormat of interest. 75 | * \return 1 if the format specified in \p format is operating with 76 | * continuous samples, otherwise 0. 77 | */ 78 | inline int mxlIsContinuousDataFormat(int format) 79 | { 80 | switch (format) 81 | { 82 | case MXL_DATA_FORMAT_AUDIO: return 1; 83 | 84 | default: return 0; 85 | } 86 | } 87 | #ifdef __cplusplus 88 | } 89 | #endif 90 | -------------------------------------------------------------------------------- /lib/internal/src/Thread.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl-internal/Thread.hpp" 5 | #include 6 | #include 7 | #include 8 | #include "mxl-internal/detail/ClockHelpers.hpp" 9 | 10 | namespace mxl::lib 11 | { 12 | namespace this_thread 13 | { 14 | void yield() noexcept 15 | { 16 | ::sched_yield(); 17 | } 18 | 19 | void yieldProcessor() noexcept 20 | { 21 | #if defined(__i386__) || defined(__x86_64__) 22 | __builtin_ia32_pause(); 23 | #elif defined(__ARM_ARCH) && (__ARM_ARCH >= 7) 24 | asm volatile("dmb ish" ::: "memory"); 25 | #else 26 | // At least emulate the side effect of a compiler 27 | // read/write barrier. 28 | asm volatile("" ::: "memory") 29 | #endif 30 | } 31 | 32 | MXL_EXPORT 33 | Duration sleep(Duration duration, [[maybe_unused]] Clock clock) noexcept 34 | { 35 | auto const sleepTime = asTimeSpec(duration); 36 | std::timespec remainder; 37 | 38 | auto const req = &sleepTime; 39 | auto const rem = &remainder; 40 | 41 | #if defined(__linux__) 42 | auto const result = ::clock_nanosleep(detail::clockToId(clock), 0, req, rem); 43 | errno = result; 44 | #elif defined(__APPLE__) 45 | auto const result = ::nanosleep(req, rem); 46 | #else 47 | # pragma GCC error No this_thread::sleep() implementation available for the current platform. 48 | #endif 49 | // Please be aware that nanosleep() and clock_nanosleep() have 50 | // different domains for their return value, but in either case 51 | // a value of 0 means the call completed successfully. 52 | return (result == 0) ? Duration{} : asDuration(remainder); 53 | } 54 | 55 | MXL_EXPORT 56 | int sleepUntil(Timepoint timepoint, Clock clock) noexcept 57 | { 58 | #if defined(__linux__) 59 | auto const sleepTime = asTimeSpec(timepoint); 60 | auto const result = ::clock_nanosleep(detail::clockToId(clock), TIMER_ABSTIME, &sleepTime, nullptr); 61 | return result; 62 | #elif defined(__APPLE__) 63 | 64 | auto const now = currentTime(clock); 65 | if (timepoint > now) 66 | { 67 | auto const sleepTime = asTimeSpec(timepoint - now); 68 | auto const result = ::nanosleep(&sleepTime, nullptr); 69 | if (result) 70 | { 71 | return errno; 72 | } 73 | } 74 | return 0; 75 | #else 76 | # pragma GCC error No this_thread::sleepUntil() implementation available for the current platform. 77 | #endif 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/internal/src/PosixDiscreteFlowWriter.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "mxl-internal/DiscreteFlowData.hpp" 11 | #include "mxl-internal/DiscreteFlowWriter.hpp" 12 | 13 | namespace mxl::lib 14 | { 15 | class FlowManager; 16 | 17 | /** 18 | * Implementation of a FlowWriter based on POSIX shared memory mapping. 19 | */ 20 | class PosixDiscreteFlowWriter final : public DiscreteFlowWriter 21 | { 22 | public: 23 | /** 24 | * Creates a PosixDiscreteFlowWriter 25 | * 26 | * \param[in] manager A referene to the flow manager used to obtain 27 | * additional information about the flows context. 28 | */ 29 | PosixDiscreteFlowWriter(FlowManager const& manager, uuids::uuid const& flowId, std::unique_ptr&& data); 30 | 31 | public: 32 | /** 33 | * Accessor for the underlying flow data. 34 | * The flow writer must first open the flow before invoking this method. 35 | */ 36 | [[nodiscard]] 37 | virtual FlowData const& getFlowData() const override; 38 | 39 | /** \see FlowWriter::getFlowInfo */ 40 | [[nodiscard]] 41 | virtual mxlFlowInfo getFlowInfo() const override; 42 | 43 | /** \see FlowWriter::getFlowConfigInfo */ 44 | [[nodiscard]] 45 | virtual mxlFlowConfigInfo getFlowConfigInfo() const override; 46 | 47 | /** \see FlowWriter::getFlowRuntimeInfo */ 48 | [[nodiscard]] 49 | virtual mxlFlowRuntimeInfo getFlowRuntimeInfo() const override; 50 | 51 | /** \see DiscreteFlowWriter::getGrainInfo */ 52 | [[nodiscard]] 53 | virtual mxlGrainInfo getGrainInfo(std::uint64_t in_index) const override; 54 | 55 | /** \see DiscreteFlowWriter::openGrain */ 56 | virtual mxlStatus openGrain(std::uint64_t in_index, mxlGrainInfo* out_grainInfo, std::uint8_t** out_payload) override; 57 | 58 | /** \see DiscreteFlowWriter::commit */ 59 | virtual mxlStatus commit(mxlGrainInfo const& mxlGrainInfo) override; 60 | 61 | /** \see DiscreteFlowWriter::cancel */ 62 | virtual mxlStatus cancel() override; 63 | 64 | /** \see FlowWriter::flowRead */ 65 | virtual void flowRead() override; 66 | 67 | virtual bool isExclusive() const override; 68 | 69 | virtual bool makeExclusive() override; 70 | 71 | private: 72 | /** The FlowData for the currently opened flow. null if no flow is opened. */ 73 | std::unique_ptr _flowData; 74 | /** The currently opened grain index. MXL_UNDEFINED_INDEX if no grain is currently opened. */ 75 | std::uint64_t _currentIndex; 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/RemoteRegion.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace mxl::lib::fabrics::ofi 13 | { 14 | 15 | /** \brief Represent a remote memory region used for data transfer. 16 | * 17 | * This can be constructed from a `RegisteredRegion`. 18 | */ 19 | struct RemoteRegion 20 | { 21 | public: 22 | /** \brief Convert this RemoteRegion to a struct fi_rma_iov used by libfabric RMA transfer functions. 23 | */ 24 | [[nodiscard]] 25 | ::fi_rma_iov toRmaIov() const noexcept; 26 | 27 | bool operator==(RemoteRegion const& other) const noexcept; 28 | 29 | public: 30 | std::uint64_t addr; 31 | std::size_t len; 32 | std::uint64_t rkey; 33 | }; 34 | 35 | class RemoteRegionGroup 36 | { 37 | public: 38 | using iterator = std::vector::iterator; 39 | using const_iterator = std::vector::const_iterator; 40 | 41 | public: 42 | RemoteRegionGroup(std::vector group) 43 | : _inner(std::move(group)) 44 | , _rmaIovs(rmaIovsFromGroup(_inner)) 45 | {} 46 | 47 | [[nodiscard]] 48 | ::fi_rma_iov const* asRmaIovs() const noexcept; 49 | 50 | bool operator==(RemoteRegionGroup const& other) const noexcept; 51 | 52 | iterator begin() 53 | { 54 | return _inner.begin(); 55 | } 56 | 57 | iterator end() 58 | { 59 | return _inner.end(); 60 | } 61 | 62 | [[nodiscard]] 63 | const_iterator begin() const 64 | { 65 | return _inner.cbegin(); 66 | } 67 | 68 | [[nodiscard]] 69 | const_iterator end() const 70 | { 71 | return _inner.cend(); 72 | } 73 | 74 | RemoteRegion& operator[](std::size_t index) 75 | { 76 | return _inner[index]; 77 | } 78 | 79 | RemoteRegion const& operator[](std::size_t index) const 80 | { 81 | return _inner[index]; 82 | } 83 | 84 | [[nodiscard]] 85 | std::size_t size() const noexcept 86 | { 87 | return _inner.size(); 88 | } 89 | 90 | private: 91 | static std::vector<::fi_rma_iov> rmaIovsFromGroup(std::vector group) noexcept; 92 | 93 | [[nodiscard]] 94 | std::vector clone() const 95 | { 96 | return _inner; 97 | } 98 | 99 | private: 100 | std::vector _inner; 101 | 102 | std::vector<::fi_rma_iov> _rmaIovs; 103 | }; 104 | } 105 | -------------------------------------------------------------------------------- /lib/tests/test_time.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | TEST_CASE("Invalid Times", "[time]") 11 | { 12 | auto const badRate = mxlRational{0, 0}; 13 | auto const badNumerator = mxlRational{0, 1001}; 14 | auto const badDenominator = mxlRational{30000, 0}; 15 | auto const goodRate = mxlRational{30000, 1001}; 16 | 17 | auto const now = mxlGetTime(); 18 | 19 | REQUIRE(mxlTimestampToIndex(nullptr, now) == MXL_UNDEFINED_INDEX); 20 | REQUIRE(mxlTimestampToIndex(&badRate, now) == MXL_UNDEFINED_INDEX); 21 | REQUIRE(mxlTimestampToIndex(&badNumerator, now) == MXL_UNDEFINED_INDEX); 22 | REQUIRE(mxlTimestampToIndex(&badDenominator, now) == MXL_UNDEFINED_INDEX); 23 | REQUIRE(mxlTimestampToIndex(&goodRate, now) != MXL_UNDEFINED_INDEX); 24 | } 25 | 26 | TEST_CASE("Index 0 and 1", "[time]") 27 | { 28 | auto const rate = mxlRational{30000, 1001}; 29 | 30 | auto const firstIndexTimeNs = 0ULL; 31 | auto const secondIndexTimeNs = (rate.denominator * 1'000'000'000ULL + (rate.numerator / 2)) / rate.numerator; 32 | 33 | REQUIRE(mxlTimestampToIndex(&rate, firstIndexTimeNs) == 0); 34 | REQUIRE(mxlTimestampToIndex(&rate, secondIndexTimeNs) == 1); 35 | 36 | REQUIRE(mxlIndexToTimestamp(&rate, 0) == firstIndexTimeNs); 37 | REQUIRE(mxlIndexToTimestamp(&rate, 1) == secondIndexTimeNs); 38 | } 39 | 40 | TEST_CASE("Test TAI Epoch", "[time]") 41 | { 42 | auto ts = std::timespec{0, 0}; 43 | tm t; 44 | gmtime_r(&ts.tv_sec, &t); 45 | 46 | REQUIRE(t.tm_year == 70); 47 | REQUIRE(t.tm_mon == 0); 48 | REQUIRE(t.tm_mday == 1); 49 | REQUIRE(t.tm_hour == 0); 50 | REQUIRE(t.tm_min == 0); 51 | REQUIRE(t.tm_sec == 0); 52 | } 53 | 54 | TEST_CASE("Index <-> Timestamp roundtrip (current)", "[time]") 55 | { 56 | auto const rate = mxlRational{30000, 1001}; 57 | 58 | auto const currentTime = mxlGetTime(); 59 | auto const currentIndex = mxlTimestampToIndex(&rate, currentTime); 60 | 61 | auto const timestamp = mxlIndexToTimestamp(&rate, currentIndex); 62 | auto const calculatedIndex = mxlTimestampToIndex(&rate, timestamp); 63 | 64 | auto const timeDelta = (currentTime > timestamp) ? currentTime - timestamp : timestamp - currentTime; 65 | REQUIRE(timeDelta < 33'366'667LL); 66 | REQUIRE(calculatedIndex == currentIndex); 67 | 68 | REQUIRE(mxlGetNsUntilIndex(currentIndex + 33, &rate) > 0); 69 | } 70 | 71 | TEST_CASE("Index <-> Timestamp roundtrip (others)", "[time]") 72 | { 73 | auto const editRate = mxlRational{30000, 1001}; 74 | 75 | for (auto i = 30'000'000U; i < 60'000'000U; ++i) 76 | { 77 | auto const ts = mxlIndexToTimestamp(&editRate, i); 78 | auto const rti = mxlTimestampToIndex(&editRate, ts); 79 | REQUIRE(i == rti); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /rust/mxl/src/grain/writer.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use std::sync::Arc; 5 | 6 | use super::write_access::GrainWriteAccess; 7 | 8 | use crate::{Error, Result, instance::InstanceContext}; 9 | 10 | /// MXL Flow Writer for discrete flows (grain-based data like video frames) 11 | pub struct GrainWriter { 12 | context: Arc, 13 | writer: mxl_sys::FlowWriter, 14 | } 15 | 16 | /// The MXL readers and writers are not thread-safe, so we do not implement `Sync` for them, but 17 | /// there is no reason to not implement `Send`. 18 | unsafe impl Send for GrainWriter {} 19 | 20 | impl GrainWriter { 21 | pub(crate) fn new(context: Arc, writer: mxl_sys::FlowWriter) -> Self { 22 | Self { context, writer } 23 | } 24 | 25 | pub fn destroy(mut self) -> Result<()> { 26 | self.destroy_inner() 27 | } 28 | 29 | /// The current MXL implementation states a TODO to allow multiple grains to be edited at the 30 | /// same time. For this reason, there is no protection on the Rust level against trying to open 31 | /// multiple grains. If the TODO ever gets removed, it may be worth considering pattern where 32 | /// opening grain would consume the writer and then return it back on commit or cancel. 33 | pub fn open_grain<'a>(&'a self, index: u64) -> Result> { 34 | let mut grain_info: mxl_sys::GrainInfo = unsafe { std::mem::zeroed() }; 35 | let mut payload_ptr: *mut u8 = std::ptr::null_mut(); 36 | unsafe { 37 | Error::from_status(self.context.api.flow_writer_open_grain( 38 | self.writer, 39 | index, 40 | &mut grain_info, 41 | &mut payload_ptr, 42 | ))?; 43 | } 44 | 45 | if payload_ptr.is_null() { 46 | return Err(Error::Other(format!( 47 | "Failed to open grain payload for index {index}.", 48 | ))); 49 | } 50 | 51 | Ok(GrainWriteAccess::new( 52 | self.context.clone(), 53 | self.writer, 54 | grain_info, 55 | payload_ptr, 56 | )) 57 | } 58 | 59 | fn destroy_inner(&mut self) -> Result<()> { 60 | if self.writer.is_null() { 61 | return Err(Error::InvalidArg); 62 | } 63 | 64 | let mut writer = std::ptr::null_mut(); 65 | std::mem::swap(&mut self.writer, &mut writer); 66 | 67 | Error::from_status(unsafe { 68 | self.context 69 | .api 70 | .release_flow_writer(self.context.instance, writer) 71 | }) 72 | } 73 | } 74 | 75 | impl Drop for GrainWriter { 76 | fn drop(&mut self) { 77 | if !self.writer.is_null() 78 | && let Err(err) = self.destroy_inner() 79 | { 80 | tracing::error!("Failed to release MXL flow writer (discrete): {:?}", err); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/internal/include/mxl-internal/FlowWriter.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "mxl-internal/FlowData.hpp" 11 | 12 | namespace mxl::lib 13 | { 14 | class MXL_EXPORT FlowWriter 15 | { 16 | public: 17 | /** 18 | * Accessor for the flow id; 19 | * \return The flow id 20 | */ 21 | [[nodiscard]] 22 | uuids::uuid const& getId() const; 23 | 24 | /** 25 | * Accessor for the underlying flow data. 26 | * The flow writer must first open the flow before invoking this method. 27 | */ 28 | [[nodiscard]] 29 | virtual FlowData const& getFlowData() const = 0; 30 | 31 | /** 32 | * Accessor for the current mxlFlowInfo. A copy of the current structure is returned. 33 | * The flow writer must first open the flow before invoking this method. 34 | * \return A copy of the mxlFlowInfo 35 | */ 36 | [[nodiscard]] 37 | virtual mxlFlowInfo getFlowInfo() const = 0; 38 | 39 | /** 40 | * Accessor for the immutable metadata that describes the currently opened flow. 41 | * The reader must be properly attached to the flow before invoking this method. 42 | * \return A copy of the mxlFlowConfigInfo of the currently opened flow. 43 | */ 44 | [[nodiscard]] 45 | virtual mxlFlowConfigInfo getFlowConfigInfo() const = 0; 46 | 47 | /** 48 | * Accessor for the current metadata that describes the current runtime state of 49 | * the currently opened flow. The reader must be properly attached to the flow before 50 | * invoking this method. 51 | * \return A copy of the current mxlFlowRuntimeInfo of the currently opened flow. 52 | */ 53 | [[nodiscard]] 54 | virtual mxlFlowRuntimeInfo getFlowRuntimeInfo() const = 0; 55 | 56 | /** 57 | * Invoked when a flow is read. The writer will 58 | * update the 'lastReadTime' field 59 | */ 60 | virtual void flowRead() = 0; 61 | 62 | /** 63 | * Check if this is the only writer for this flow. 64 | */ 65 | virtual bool isExclusive() const = 0; 66 | 67 | /** 68 | * Try to turn this into a exclusive writer. 69 | * \return true if the operation was successful and this is the only writer, false if the operation was not successful because there are other 70 | * active writers for this flow. 71 | */ 72 | virtual bool makeExclusive() = 0; 73 | 74 | /** Destructor. */ 75 | virtual ~FlowWriter(); 76 | 77 | protected: 78 | explicit FlowWriter(uuids::uuid&& flowId); 79 | explicit FlowWriter(uuids::uuid const& flowId); 80 | 81 | private: 82 | uuids::uuid _flowId; 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /lib/internal/src/FlowOptionsParser.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "mxl-internal/FlowOptionsParser.hpp" 5 | #include 6 | #include 7 | #include "mxl-internal/Logging.hpp" 8 | 9 | namespace mxl::lib 10 | { 11 | FlowOptionsParser::FlowOptionsParser(std::string const& in_options) 12 | { 13 | if (in_options.empty()) 14 | { 15 | return; 16 | } 17 | 18 | // 19 | // Parse the json options 20 | // 21 | auto jsonValue = picojson::value{}; 22 | auto const err = picojson::parse(jsonValue, in_options); 23 | if (!err.empty()) 24 | { 25 | throw std::invalid_argument{"Invalid JSON options. " + err}; 26 | } 27 | 28 | // Confirm that the root is a json object 29 | if (!jsonValue.is()) 30 | { 31 | throw std::invalid_argument{"Expected a JSON object"}; 32 | } 33 | _root = jsonValue.get(); 34 | 35 | auto maxCommitBatchSizeHintIt = _root.find("maxCommitBatchSizeHint"); 36 | if (maxCommitBatchSizeHintIt != _root.end()) 37 | { 38 | if (!maxCommitBatchSizeHintIt->second.is()) 39 | { 40 | throw std::invalid_argument{"maxCommitBatchSizeHint must be a number."}; 41 | } 42 | 43 | auto const v = maxCommitBatchSizeHintIt->second.get(); 44 | if (v < 1) 45 | { 46 | throw std::invalid_argument{"maxCommitBatchSizeHint must be greater or equal to 1."}; 47 | } 48 | _maxCommitBatchSizeHint = static_cast(v); 49 | } 50 | 51 | auto maxSyncBatchSizeHintIt = _root.find("maxSyncBatchSizeHint"); 52 | if (maxSyncBatchSizeHintIt != _root.end()) 53 | { 54 | if (!maxSyncBatchSizeHintIt->second.is()) 55 | { 56 | throw std::invalid_argument{"maxSyncBatchSizeHint must be a number."}; 57 | } 58 | 59 | auto const v = maxSyncBatchSizeHintIt->second.get(); 60 | if (v < 1) 61 | { 62 | throw std::invalid_argument{"maxSyncBatchSizeHint must be greater or equal to 1."}; 63 | } 64 | _maxSyncBatchSizeHint = static_cast(v); 65 | if ((_maxSyncBatchSizeHint.value() % _maxCommitBatchSizeHint.value_or(1) != 0)) 66 | { 67 | throw std::invalid_argument{"maxSyncBatchSizeHint must be a multiple of maxCommitBatchSizeHint."}; 68 | } 69 | } 70 | } 71 | 72 | std::optional FlowOptionsParser::getMaxCommitBatchSizeHint() const 73 | { 74 | return _maxCommitBatchSizeHint; 75 | } 76 | 77 | std::optional FlowOptionsParser::getMaxSyncBatchSizeHint() const 78 | { 79 | return _maxSyncBatchSizeHint; 80 | } 81 | } // namespace mxl::lib 82 | -------------------------------------------------------------------------------- /lib/fabrics/ofi/src/internal/MemoryRegion.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 Contributors to the Media eXchange Layer project. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "Domain.hpp" 12 | #include "Region.hpp" 13 | 14 | namespace mxl::lib::fabrics::ofi 15 | { 16 | 17 | /** \brief RAII wrapper around a libfabric memory region (`fid_mr`) 18 | */ 19 | class MemoryRegion 20 | { 21 | public: 22 | /** \brief Register a memory region with a specified domain and access permissions. 23 | * 24 | * \param domain The domain to register the memory region with. 25 | * \param region The region to register. 26 | * \param access The access permissions for the memory region. Possible values are: 27 | * - FI_SEND: The memory buffer may be used in outgoing message data transfers. 28 | * - FI_RECV: The memory buffer may be used to receive inbound message transfers. 29 | * - FI_WRITE: The memory buffer may be used as the source buffer for RMA write and atomic operations on the initiator side. 30 | * - FI_REMOTE_READ: The memory buffer may be used as the source buffer of an RMA read operation on the target side. 31 | * - FI_REMOTE_WRITE: The memory buffer may be used as the target buffer of an RMA write operation on the target side. 32 | * 33 | * \return A MemoryRegion object representing the registered memory region. 34 | */ 35 | static MemoryRegion reg(Domain& domain, Region const& region, std::uint64_t access); 36 | 37 | ~MemoryRegion(); 38 | 39 | MemoryRegion(MemoryRegion const&) = delete; 40 | void operator=(MemoryRegion const&) = delete; 41 | 42 | MemoryRegion(MemoryRegion&&) noexcept; 43 | MemoryRegion& operator=(MemoryRegion&&) noexcept; 44 | 45 | /** \brief Access the underlying raw `fid_mr` pointer. 46 | */ 47 | [[nodiscard]] 48 | ::fid_mr* raw() noexcept; 49 | /** \copydoc raw() */ 50 | [[nodiscard]] 51 | ::fid_mr const* raw() const noexcept; 52 | 53 | /** \brief Get the descriptor associated with the memory region. 54 | */ 55 | [[nodiscard]] 56 | void* desc() const noexcept; 57 | 58 | /** \brief Get the remote key (rkey) associated with the memory region. 59 | * 60 | * Thisthe mechanism for protecting a registered region. One should be careful and should only share this secret with initiators that are 61 | * allowed to access this memory region. 62 | */ 63 | [[nodiscard]] 64 | std::uint64_t rkey() const noexcept; 65 | 66 | private: 67 | friend class RegisteredRegion; 68 | 69 | private: 70 | /** \brief Internal method to release the memory region. 71 | */ 72 | void close(); 73 | 74 | MemoryRegion(::fid_mr* raw); 75 | 76 | private: 77 | ::fid_mr* _raw; 78 | }; 79 | } 80 | --------------------------------------------------------------------------------