Files
go-mxl-player/README_public.md
T
2026-09-05 18:50:45 +03:00

9.6 KiB

MXL Player

MXL Player is a desktop player for local Media eXchange Layer audio and video flows, with GUI controls and command-line startup configuration. It can play either feed independently, play both simultaneously, or switch a configured pair into and out of native MXL synchronization while running.

The application uses:

  • SDL3 for its window, input, and audio output;
  • Vulkan for video and ImGui rendering;
  • go-mxl for MXL access.

Features

  • Synchronized playback for compatible same-domain feeds; cross-domain feeds currently use independent readers.
  • Finite or unlimited reconnect attempts with exponential backoff.
  • JSON playlists with manual selection, timed advance, looping, and failure policies.
  • Playback, media, timing, retry, and dropped-frame statistics.

Planned

  • MXL Fabrics support;
  • MXL URI/addressability support;
  • Coordinated cross-domain reading using TAI timestamps;
  • GUI-created playlist;
  • GPU selection;
  • LUFS meter;
  • patching audio channels to selected device.

Installation

Prebuilt packages are available from GitHub Releases.

  • macOS ARM64: .app bundle with SDL3, libmxl, and MoltenVK included.
  • Linux AMD64: binary built on Ubuntu. A compatible libmxl installation, SDL3, Vulkan loader, and Vulkan-capable driver are required.

Download the archive for your platform and verify its SHA-256 checksum before running it.

Tested platforms

  • Ubuntu and Fedora: build and feed playback tested.
  • macOS ARM64: build and feed playback tested.

Building from source: requirements

  • Go 1.26 or newer.
  • A C/C++ build toolchain for cgo dependencies.
  • A compatible shared build of libmxl and its development headers.
  • pkg-config metadata for libmxl.
  • SDL3 shared library.
  • Vulkan loader and a working Vulkan driver.
  • libmxl 1.2.0 or a compatible build providing mxlCreateFlowSynchronizationGroup.

The project currently pins:

github.com/qvest-digital/go-mxl v1.1.0-rc.2

Building on Linux

First verify that pkg-config resolves the intended MXL installation:

pkg-config --modversion libmxl
pkg-config --cflags --libs libmxl
pkg-config --variable=pcfiledir libmxl
pkg-config --variable=libdir libmxl

If MXL is installed in a nonstandard prefix:

export MXL_PREFIX=/opt/mxl/1.2.0
export PKG_CONFIG_PATH="$MXL_PREFIX/lib/pkgconfig"
export LD_LIBRARY_PATH="$MXL_PREFIX/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"

Then build and test:

go mod download
go test ./...
mkdir -p build
go build -o build/mxl-player ./cmd/mxl-player

Confirm which native library the executable will use:

ldd build/mxl-player | grep libmxl

macOS

The SDL3 and Vulkan loaders contain macOS library-name support. The Vulkan dependency is temporarily replaced by a portability fork while the upstream change is reviewed.

Building currently requires:

  • Xcode Command Line Tools;
  • Go;
  • SDL3;
  • MoltenVK;
  • a macOS build of libmxl with matching headers and pkg-config metadata.

When libmxl has been built from its source tree but has not been installed into a standard prefix, expose its build metadata, source headers, and library directory to cgo. For example:

export MXL_SOURCE=/path/to/mxl
export MXL_BUILD="$MXL_SOURCE/build/Darwin-Clang-Release"

export PKG_CONFIG_PATH="$MXL_BUILD${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
export CGO_CFLAGS="-I$MXL_SOURCE/lib/include"
export CGO_LDFLAGS="-L$MXL_BUILD/lib"

mkdir -p build
go build -o build/mxl-player ./cmd/mxl-player

The CGO_CFLAGS workaround is needed because the headers are still in the MXL source tree. A properly installed MXL SDK should expose them through libmxl.pc instead.

Nonstandard loader locations can be supplied explicitly (for example, in case of installing with homebrew):

export SDL3_LIBRARY="$(brew --prefix sdl3)/lib/libSDL3.dylib"
export VULKAN_LIBRARY=/absolute/path/to/libMoltenVK.dylib
export DYLD_LIBRARY_PATH="$MXL_BUILD/lib${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"

./build/mxl-player

The resulting executable may currently need an additional libmxl runtime search path, for example:

install_name_tool -add_rpath "$MXL_BUILD/lib" build/mxl-player

These workarounds are only needed for development builds. The packaged .app uses bundled libraries and relative runtime paths instead.

Running the macOS application bundle

The package is ad-hoc signed but is not signed with an Apple Developer ID or notarized by Apple. Consequently, Gatekeeper may block its first launch. Right-click MXL Player.app, select Open, and confirm the prompt. It can also be allowed from System Settings → Privacy & Security after a blocked launch.

If macOS still retains a quarantine restriction, it can be removed manually:

xattr -dr com.apple.quarantine "/Applications/MXL Player.app"

Only remove quarantine from an archive downloaded from the official project release and verified against its SHA-256 checksum.

Running

Start with no configured feed and enter domains/UUIDs in the GUI:

./build/mxl-player

Video only:

./build/mxl-player \
  --domain /dev/shm/mxl \
  --video VIDEO_UUID

Audio only:

./build/mxl-player \
  --domain /dev/shm/mxl \
  --audio AUDIO_UUID

Independent video and audio:

./build/mxl-player \
  --video-domain /dev/shm/video \
  --video VIDEO_UUID \
  --audio-domain /dev/shm/audio \
  --audio AUDIO_UUID

Start a compatible pair synchronized:

./build/mxl-player \
  --domain /dev/shm/mxl \
  --video VIDEO_UUID \
  --audio AUDIO_UUID \
  --sync

Synchronization is not a permanent startup mode. It can be enabled and disabled at runtime from the settings window.

Command-line options

Option Short Meaning
--help -h Show help and exit.
--domain PATH -d Default domain for feeds without a specific domain.
--video-domain PATH Domain for the video feed.
--audio-domain PATH Domain for the audio feed.
--video UUID -v Initial video flow UUID.
--audio UUID -a Initial audio flow UUID.
--sync -s Start a configured A/V pair synchronized.
--max-attempts N Attempts per playback lifecycle; 0 means unlimited.
--playlist FILE Load a JSON playlist.
--fullscreen -f Start fullscreen.
--gpu-id N -g Select GPU ID; currently incomplete.
--playback-id N -p Select the SDL playback-device ID.
--list-playback List SDL playback devices and exit.
--list-gpu List Vulkan physical devices and exit.
--verbose Reserved; currently incomplete.

Run ./build/mxl-player --help for the authoritative list.

GUI controls

The settings window accepts separate video/audio domains and UUIDs.

  • Apply feeds applies the complete desired configuration.
  • Stop stops a feed while retaining its UUID and domain.
  • Resume starts a stopped configured feed with a fresh lifecycle.
  • Remove stops a feed and clears its configuration.
  • Stop all and Resume all operate on both configured feeds.
  • Synchronize switches a compatible active pair between synchronized and independent playback.

Keyboard shortcuts:

Key Action
F1 Show or hide settings.
F2 Show or hide statistics.
F Toggle fullscreen.
Q or Esc Quit.

Retry behavior

Each playback lifecycle starts at attempt 1. Failed connections/readers are retried with exponential delay from 500 ms up to 5 seconds.

# Retry indefinitely
./build/mxl-player -d /dev/shm/mxl -v VIDEO_UUID --max-attempts 0

# Stop after three failed attempts
./build/mxl-player -d /dev/shm/mxl -v VIDEO_UUID --max-attempts 3

With independent A/V, one failed feed retries without stopping the other. A synchronized pair reconnects as one lifecycle.

Playlists

Start a playlist with:

./build/mxl-player --playlist playlist.json

Example:

{
  "loop": true,
  "on_failure": "next",
  "retry": {
    "max_attempts": 3,
    "initial_delay": "500ms",
    "max_delay": "5s"
  },
  "entries": [
    {
      "name": "Synchronized pair",
      "video": {
        "domain": "/dev/shm/mxl",
        "uuid": "VIDEO_UUID"
      },
      "audio": {
        "domain": "/dev/shm/mxl",
        "uuid": "AUDIO_UUID"
      },
      "sync": true,
      "duration": "10s"
    },
    {
      "name": "Video only",
      "video": {
        "domain": "/dev/shm/mxl",
        "uuid": "ANOTHER_VIDEO_UUID"
      },
      "duration": "15s"
    },
    {
      "name": "Audio until manually advanced",
      "audio": {
        "domain": "/dev/shm/mxl",
        "uuid": "ANOTHER_AUDIO_UUID"
      }
    }
  ]
}

Playlist rules:

  • duration uses Go duration syntax such as 500ms, 10s, or 2m.
  • Missing/empty duration means manual advance.
  • loop: true returns to the first entry after the last.
  • on_failure: "wait" remains on an exhausted entry.
  • on_failure: "next" advances after retry exhaustion.
  • A synchronized entry must contain both video and audio.
  • Playlist retry settings override the CLI defaults unless --max-attempts was explicitly supplied.

The GUI supports entry selection, previous/next navigation, and pausing or resuming a timed entry.

Third-party assets

The embedded JetBrainsMonoNL Nerd Font Mono is distributed under the SIL Open Font License 1.1. Its copyright notice, license, and source information are in internal/assets/fonts.

License

MXL Player is licensed under the GNU General Public License, version 3 or any later version. See LICENSE.

The embedded font retains its separate SIL Open Font License 1.1.