-
Notifications
You must be signed in to change notification settings - Fork 0
Comparing changes
Open a pull request
base repository: OpenSoundStack/OpenAudioLiveSystem
base: master
head repository: OpenSoundStack/OpenAudioLiveSystem
compare: feature/dynamic-routing
- 19 commits
- 46 files changed
- 1 contributor
Commits on Jun 3, 2026
-
Migrate engine + io_sim to oals::rt shim (M1 of dev-tooling plan)
Replace inline sched_setscheduler/sched_setaffinity/clock_nanosleep calls with calls into the new oals::rt namespace from OpenAudioNetwork/netutils/platform/rt.h. Delete the local set_thread_realtime/set_running_cpu helpers and the #include <linux/sched.h> in both files. No behavior change on Linux: same SCHED_FIFO priorities (engine 25/20/80, io_sim 50), same SCHED_RR (99, io_sim main), same CPU affinities (engine 1/1/2/3), same CLOCK_MONOTONIC relative sleeps (100 ns + 10000 ns in engine, ~667 µs in io_sim). Plus bumped OpenAudioNetwork submodule pointer to the matching M1 commit that introduces the shim and the NOT EMBEDDED_BUILD gate. After M1+M2 the engine and io_sim will compile on macOS; linking still depends on M3's transport seam (the four extern "C" hooks that LowLatSocket's #else arm currently references but doesn't define on non-Linux hosts). See Docs/dev-tooling-plan.md M1.
Configuration menu - View commit details
-
Copy full SHA for fdcf7b8 - Browse repository at this point
Copy the full SHA fdcf7b8View commit details -
Make engine + io_sim compile on macOS (M2 of dev-tooling plan)
CMake plumbing + source hygiene so the OALS tree configures and compiles on macOS up to the M3-scope link gap. Linking still depends on M3's transport seam (__send_data / __recv_data / __fetch_iface_meta and NetworkMapper::get_mac_by_uid remain undefined on non-Linux hosts). Top-level CMakeLists.txt: - Gate the aarch64 / -ftree-vectorize block with AND NOT APPLE so it no longer fires on Apple Silicon (which reports as aarch64 on some toolchains, arm64 on others; either way Apple Clang auto-vectorizes at -O2+, so the flag is redundant). Linux ARM (Pi, embedded) still picks it up. - Add option(OAN_HOST_BACKENDS "Build host dev transports + RT shim" OFF), force ON via CACHE BOOL ... FORCE when APPLE so subdirectory scopes see the override (a plain set() shadows but does not update the cache), propagate as add_compile_definitions. No code consumes the macro yet — it is plumbing for M3 transport sources. io_sim ALSA dead-code purge: The dev-tooling plan claimed io_sim's ALSA use was "already entirely commented out." That was wrong — only the call and the playback_thread consuming it were commented; the snd_pcm_t* alsa_setup() function body and #include <alsa/asoundlib.h> were live. Decision was to delete outright rather than wrap in #ifdef __linux__: io_sim is marked deprecated in CLAUDE.md, the VSC track supersedes its playback path, and ALSA cannot exist on macOS. Removes -107 lines from io_sim/main.cpp plus the ALSA pkg_check_modules and link in io_sim/CMakeLists.txt. SNDFILE stays REQUIRED (used live by gen_packet_strm_from_file for stem playback; available on macOS via brew install libsndfile). SNDFILE include-dir propagation: io_sim and debugger now pass ${SNDFILE_INCLUDE_DIRS} into target_include_directories. Linux happened to work because /usr/include is searched by default; Homebrew installs to /opt/homebrew/include which is not. Qt include de-Debianisation in plugins/loader/PipeDesc.h: #include <qt6/QtGui/QPainter> etc. was Debian/Ubuntu-specific (their Qt6 headers live under /usr/include/qt6/). Standard Qt6 CMake config — used by Homebrew, Arch, Fedora, Alpine, and upstream Qt — adds the include dir directly and expects the canonical <QtGui/QPainter> form. Linux Debian/Ubuntu users keep working because Qt6::Widgets is already linked everywhere these headers are used. Two missing #include <iostream>: engine/NetMan.cpp and debugger/DebuggerWindow.cpp use std::cerr / std::cout but did not include <iostream>. Previously transitive via other headers; the Mac build path no longer pulls it in. Direct include is correct hygiene. Plus .gitignore for build/ dirs. Verified on macOS: cmake configure + cmake --build produces 72 .cpp.o files with 0 compile errors. Only failures are the documented M3-scope undefined symbols at the oannetutils.dylib link step. See Docs/dev-tooling-plan.md M2.Configuration menu - View commit details
-
Copy full SHA for d974e60 - Browse repository at this point
Copy the full SHA d974e60View commit details -
Propagate sndfile lib dirs + bump OAN to M3 (M3 of dev-tooling plan)
Bump OpenAudioNetwork submodule to the M3 commit that introduces the ITransport seam, so OALSEngine, io_simulator, OALSCoreUI, debugger, and the builtin plugins all link cleanly on macOS for the first time (M2 only got them to compile; oannetutils.dylib was failing to link with four undefined symbols — __send_data, __recv_data, __fetch_iface_meta, NetworkMapper::get_mac_by_uid). After M3 the SimTransport stub is reachable: ./OALSEngine sim:default routes through it and exits cleanly with a "not yet implemented (M4)" message. Plain ifname on Mac fails loudly with a clear "this host requires a transport prefix" message. Plus a CMake fix the M3 link surfaced: target_link_directories with ${SNDFILE_LIBRARY_DIRS} on both io_simulator and debugger. M2 added ${SNDFILE_INCLUDE_DIRS} for the compile step but missed the parallel ${SNDFILE_LIBRARY_DIRS} for the link step. On Linux this happened to work because /usr/lib is searched by default; on Mac, Homebrew's /opt/homebrew/lib is not. Without this, `ld: library 'sndfile' not found` blocks io_simulator and debugger from linking. M2 didn't surface this because the M2 link gap stopped earlier in the chain. See OpenAudioLiveSystem/Docs/dev-tooling-plan.md M3 and the OAN submodule's M3 commit (61ed291) for the transport seam details.Configuration menu - View commit details
-
Copy full SHA for 8d0cc4e - Browse repository at this point
Copy the full SHA 8d0cc4eView commit details -
Add sim_switch daemon + macOS dev-loop fixes (M4 of dev-tooling plan)
New tools/sim_switch/ — single-threaded poll() user-space switch daemon emulating a switched L2 segment over AF_UNIX. Pure POSIX, builds on Linux + macOS. Live TUI with traffic rates, device discovery decode, per-conn drop counters; --headless mode for CI. 7-scenario GTest smoke suite (hello, broadcast, unicast, unknown-unicast, bad magic, slow client, SimTransport interop). Submodule bump pulls in OAN's real SimTransport implementation. Wire framing (sim_proto.h) is owned here, not in OAN — OAN is vendored into firmware repos and must stay free of host-dev-only contracts. SimTransport keeps a byte-identical local copy. Also in this commit (M4 verification follow-ups discovered on macOS): - ENGINE_PLUGIN_SYSLOCATION is now $HOME/.osst/core_plugins on APPLE; the Linux /core_plugins path can't be created on macOS's sealed root volume. Linux target unchanged. - io_simulator now respects argv[1] as the interface string, matching OALSEngine. Previously hardcoded to 'virbr0'. - coreui/surface_config/surface.json uses sim:default as the default eth_interface so the UI works out of the box on macOS. Linux dev loops can override per-host. - Top-level enable_testing() so ctest discovers sim_switch_smoke reliably across CMake versions.
Configuration menu - View commit details
-
Copy full SHA for 63e87d7 - Browse repository at this point
Copy the full SHA 63e87d7View commit details -
io_sim: load tracks from JSON config + bump OAN submodule
io_sim's wav paths were hardcoded to a developer's home dir, so it exited on every other machine. Replace with a JSON config (argv[2], default ./io_sim.json) that lists tracks as either {channel, path} or {channel, tone: {freq, gain}}. - nlohmann/json pulled in via FetchContent (header-only, dev-only tool so the dep is acceptable; coreui still uses QJsonDocument). - Tilde-expand paths so ~/Music/... works directly. - Reject non-96k wavs with the exact ffmpeg command needed to convert. - Tone-gen tracks for "is the wire alive?" testing without wavs. - Loops normalized to shortest stream so the cursor wraps cleanly. - io_sim.example.json: 4-channel tone demo (440/880/1k/1.5k Hz). Submodule bump pulls in the NetworkMapper disco/age-loop throttle on host backends.Configuration menu - View commit details
-
Copy full SHA for 64a4bd7 - Browse repository at this point
Copy the full SHA 64a4bd7View commit details -
Add oaninspect + switch TUI overhaul (M5 of dev-tooling plan)
sim_switch: - SimFrame v2: switch populates src_uid, so observers see who sent. - SimHello v2: flags field with SIM_HELLO_PROMISCUOUS for inspectors that want every fanout regardless of ethertype / dst_uid. - Per-peer tx/rx stat counters per ethertype, attributed during consume_frame and try_write. Pruned alongside disco entries. - TUI rates smoothed via EWMA (α=0.15, ~1s window) so disco's bursty 5-sec interval no longer makes the dashboard oscillate between 20/s and 0/s. - New Peers table sorted by uid with A/D/C/S tx/rx columns — actual data-flow visibility for installations with more than 2 nodes. - "Inspectors: N attached" line. oaninspect (new tool): - Connects as a promiscuous client, ANSI-coloured per-EtherType pretty-print of every frame. - Filter expression with key=value[,value,...] grammar (ethertype/ src/dst/peer/uid). Default suppresses audio. - Audio fast-path: when filter excludes audio, skip at ingest (4000 frames/s) so the 100k ring holds plenty of disco/sync/ control history — audio still counted for the suppression hint. - Pause stops ring ingest (with pending counter), so the frozen view stays frozen even at high wire rates. Filter changes re-filter the existing ring so they work while paused. - Diff-render: only redraws rows whose content changed, no full-screen clear flicker. - Interactive: Space pause, j/k scroll, Ctrl-D/U half-page, g/G top/end, / re-filter, h hex, q quit. Cheat-sheet footer. - Non-TTY fallback: prints plain decoded lines to stdout for CI. - --pcap record / --replay (own binary format). Tests: - +7 switch scenarios (promiscuous receives broadcasts + unicasts to others, src_uid populated by switch, multi- inspector, no loopback, promiscuous not in route table, v1 hello rejected). - 6 Filter parser unit tests. - 3 EWMA unit tests. - 23/23 passing. OAN submodule bump pulls in the matching SimFrame v2 / SimHello v2 on the engine + io_sim + UI side.Configuration menu - View commit details
-
Copy full SHA for cf2ef7c - Browse repository at this point
Copy the full SHA cf2ef7cView commit details -
Stop RT threads busy-spinning on host backends (M6 of dev-tooling plan)
OALSEngine idle on macOS was burning ~150 % CPU (and ~350 % with audio flowing) because three loops weren't actually paced: - main thread: while(true) NetMan::update_netman() — the function body is empty. Pure busy spin, one full core. - pipe_updater: precise_sleep_ns(100) between update_processes() walks of all 64 disabled pipes. nanosleep floor on macOS is ~3 µs, so it ticked at ~300 kHz. - clock_syncer: ClockMaster::sync_process() does an async recv that returns 0 on EAGAIN; the 10 µs precise_sleep_ns between calls couldn't keep up. io_sim's clock_thread had the same async-recv spin with no sleep at all. The four real RT recv threads (audiopoll, controlpoll, packet_receiver) were already cold — they call receive_data(async=false) which blocks in the kernel correctly via SimTransport::recv's existing poll(-1). All four fixes are gated by OAN_HOST_BACKENDS so the Linux RT path is byte-identical. AudioEngine gains a CV pair (notify_block_ready / wait_for_block); feed_pipe signals it from the audio recv callback so pipe_updater can block instead of ticking. NetMan gains clock_wait_or_tick(timeout_ms) that drains the sync poll-spin via ClockMaster::wait_sync_readable before running the 1 s heartbeat. Main thread parks on pause(). io_sim's clock_thread does the same wait_sync_readable wrap. Measured on macOS, OALSEngine: - idle (no io_sim): 151 % → 0.9 % - with io_sim audio flowing: ~350 % → 6.0 % Audio throughput preserved (~3960 audio frames/s on the switch). All 23 sim_switch tests still green.Configuration menu - View commit details
-
Copy full SHA for 27ef9c7 - Browse repository at this point
Copy the full SHA 27ef9c7View commit details -
Add --help on engine + io_sim, scripts/dev-up.sh, bump OAN for M7
OALSEngine and io_simulator now print a real usage block on --help instead of trying to parse the flag as an interface name. Both explain the sim:<name> transport spec inline so contributors don't need to dig in CLAUDE.md. scripts/dev-up.sh launches the 3-process stack (sim_switch + OALSEngine + io_simulator, optionally + oaninspect) in a tmux session. Idempotent: --down kills the session and clears the socket; re-running cleans up stale processes first. Per-pane logs tee'd to /tmp/osst-dev-<role>.log. OAN bump pulls in the M7 Mac RT shim (THREAD_TIME_CONSTRAINT_POLICY + mlockall). No engine call site change — set_thread_realtime now actually applies a budget on Mac instead of being a no-op.
Configuration menu - View commit details
-
Copy full SHA for 458d1c5 - Browse repository at this point
Copy the full SHA 458d1c5View commit details -
Add CI, clang-format, pre-commit hooks
CI: GitHub Actions runs on every push and PR to any branch, on ubuntu-latest + macos-latest. Installs cmake, ninja, qt6, libsndfile, gtest from package managers, then configures with OAN_HOST_BACKENDS=ON, builds, and runs ctest. clang-format: LLVM-based, K&R braces, 100-col limit, left-aligned references (auto& is the codebase majority). Editor-on-save only — no mass reformat. pre-commit: clang-format + trailing-whitespace + EOF fixer + merge- conflict + large-file guard. Excludes the OAN submodule (it has its own config). Install via 'pip install pre-commit && pre-commit install'.
Configuration menu - View commit details
-
Copy full SHA for 4041b39 - Browse repository at this point
Copy the full SHA 4041b39View commit details -
sim_switch_test: link oancommon for NetworkMapper symbol
Linux ld is strict about undefined references in shared libs; oannetutils' LowLatSocket pulls in NetworkMapper::get_mac_by_uid which lives in oancommon. macOS' -undefined,dynamic_lookup link option hid this until CI tried a real Linux build.
Configuration menu - View commit details
-
Copy full SHA for 712d7c5 - Browse repository at this point
Copy the full SHA 712d7c5View commit details -
Configuration menu - View commit details
-
Copy full SHA for 96b178c - Browse repository at this point
Copy the full SHA 96b178cView commit details -
Configuration menu - View commit details
-
Copy full SHA for 85cddf1 - Browse repository at this point
Copy the full SHA 85cddf1View commit details -
sim_switch_test: --no-as-needed on Linux for transitive OAN link
Real root cause of the Linux link failure: GNU ld defaults to --as-needed since binutils 2.31. sim_switch_test's own code doesn't reference any oancommon symbol directly, so the linker would drop liboancommon.so from the link line — and the transitive reference from oannetutils' LowLatSocket::get_mac to NetworkMapper::get_mac_by_uid stayed unresolved. Wrap both OAN .so's in --no-as-needed/--as-needed on Linux so both are pinned in. macOS' ld64 has no --as-needed concept; plain list is fine there. Previous attempts (--unresolved-symbols=ignore-in-shared-libs, then -z undefs at the .so level) only addressed building the .so itself, not the executable link step. OAN submodule bump: just a comment refresh in netutils/CMakeLists.
Configuration menu - View commit details
-
Copy full SHA for d2529c7 - Browse repository at this point
Copy the full SHA d2529c7View commit details
Commits on Jun 4, 2026
-
Bump OAN + add OAN_UID_AUTOCONF top-level option
Phase 1 of UID autoconfiguration lands in OpenAudioNetwork behind the new OAN_UID_AUTOCONF flag (default OFF). Mirror the option here so the parent build can propagate it; bump the submodule pointer to pick up the new structs, algorithm, and tests. See Docs/proposals/uid-autoconfiguration.md and -impl.md.
Configuration menu - View commit details
-
Copy full SHA for 4bc09d3 - Browse repository at this point
Copy the full SHA 4bc09d3View commit details -
Wire UID autoconfiguration into engine, UI, and io_sim (phase 2)
Engine, coreui, and io_sim now derive their OAN UID via the autoconfig algorithm (MAC-hash + collision probe) on first boot and persist it for subsequent boots. The flag OAN_UID_AUTOCONF defaults ON for Linux and host-backend dev builds; firmwares stay OFF and wire it themselves in phase 3. - engine: NetMan owns the autoconfig step; main.cpp constructs an EnvOverrideUidStore over a FileUidStore at /var/lib/oals/engine-<iface>.uid (Linux) or ~/.local/state/oals/engine-<iface>.uid (host), and defers AudioRouter construction until NetMan has committed a UID. Removes the hardcoded uid=100. - coreui: ShowManager wraps surface.json with a QJsonFieldUidStore (QSaveFile atomic write of network.persisted_uid). NetworkConfig splits hint_uid (static-range pin from network.uid) from persisted_uid and the committed uid. Static-range hints bypass the probe phase. - io_sim: inline JsonFieldUidStore over the config JSON (atomic temp+rename), removes the long-standing hardcoded uid=1, fixes ClockSlave to use the committed UID, moves launch_mapping_process after autoconfig. - All three accept --renumber to clear the persisted UID and re-derive.
Configuration menu - View commit details
-
Copy full SHA for 95bf652 - Browse repository at this point
Copy the full SHA 95bf652View commit details -
Drop OAN_UID_AUTOCONF flag from console + bump OAN (phase 4)
UID autoconfiguration is now unconditional in engine, coreui, and io_sim. Removes the option() in top-level CMakeLists.txt, the #ifdef blocks across all three binaries, and the legacy uid=100/uid=200/uid=1 fallback paths. - engine/NetMan: init_netman is now a single overload that always takes an IUidStore* (nullable for tests). Deleted the m_pconf.uid = 100 branch. - engine/main: unconditional FileUidStore + EnvOverrideUidStore wiring. - coreui/ShowManager: unconditional QJsonFieldUidStore over surface.json. network.uid is honoured only as a static-range pin; dynamic values are silently ignored by the configurator. - io_sim: unconditional JsonFieldUidStore over the config JSON. - surface.json: strip the now-meaningless uid=200 default. - example.json: update the comment to clarify static-pin behaviour. Bumps OAN submodule to 1b824ac (the matching OAN-side phase 4 commit). Firmwares are unaffected; they pin pre-phase-1 OAN and will autoconfigure once their submodules get bumped in phase 3.
Configuration menu - View commit details
-
Copy full SHA for 48ff5ca - Browse repository at this point
Copy the full SHA 48ff5caView commit details -
sim_switch: adopt conn UID from MAPPING payload on disco
A peer's discovery socket is created by NetworkMapper before UID autoconfig runs, so the hello on that conn carries uid=0. The committed UID first appears on the wire inside MAPPING packets sent on the same conn. Without adoption, every engine's disco conn stays registered as uid=0 in the switch for the rest of the session, which breaks unicast disco routing (last-zero-wins in the route table) and makes the TUI aggregate every engine into one fake "uid=0 (unknown)" peer. When a MAPPING packet arrives on a non-promiscuous disco conn whose self_uid is still 0, parse the payload's self_uid and adopt it: drop the stale (disco, 0) route entry if it still points to us, install the new (disco, learned_uid) entry, and let the subsequent src_uid overwrite + peer-stats attribution use the real identity. Verified end-to-end: two engines on one sim_switch now each surface under their autoconfigured UIDs in oaninspect's disco stream instead of both showing src_uid=0.
Configuration menu - View commit details
-
Copy full SHA for 9e3d164 - Browse repository at this point
Copy the full SHA 9e3d164View commit details -
Add dynamic audio routing + bus auto-route
Replaces the implicit per-channel-number audio dispatch that broke when phase-4 UID autoconfig removed the engine=100 / iosim=1 hardcodes. Engine: AudioEngine gains a per-pipe input-route table (atomic uint32 array, lock-free reads on the audio hot path). feed_pipe() now takes the sender's UID and consults the table on (src_uid, src_ch); pipes with no route entry receive nothing. Engine is deaf by default. - Engine advertises phy_in_count = phy_out_count = AUDIO_ENGINE_MAX_PIPES so the Routing UI sees 64 logical in/out endpoints. - install_pipe() clears any stale route in the slot it claims, so a reused pipe doesn't silently inherit a previous occupant's input. - PIPE_ALLOC_RESET also wipes all input routes. - New control-query handlers for SET_INPUT_ROUTE / CLEAR_INPUT_ROUTE delegate to AudioEngine. io_sim: removed hardcoded send to UID 100. Now silent until SET_AUDIO_DEST arrives over the control channel. Added a small control-poll thread that decodes ControlQueryPacket directly off the control socket without bringing in a full AudioRouter. UI: new RoutingPage with source/target dropdowns of every discovered peer and a click-to-route matrix sized by phy_in_count / phy_out_count. Single-active-dest-per-source + column-exclusive rules enforced visually; engine independently enforces "one source per pipe slot." Wrapped in a QScrollArea so 64x64 engine matrices stay sane. UI: ShowManager auto-fires SET_INPUT_ROUTE when a bus pipe (first elem flagged ELEM_IS_INPUT_MATRIX) is registered, restoring same-engine send-mtx -> bus operation. All senders targeting (host, bus_channel) share one route entry; the bus's input matrix sums them. new_show() now picks the DSP via find_free_dsp() instead of sending PIPE_ALLOC_RESET to the leftover hardcoded UID 100. oaninspect decodes the new query types and prints richer CONTROL payload (LEVEL flag, dtype-aware data field). .gitignore: io_sim*.json runtime configs (template stays at io_sim/io_sim.example.json). See Docs/proposals/dynamic-routing.md for the full design + open items (persistence, list-routes-back, multi-UI last-writer-wins debt).Configuration menu - View commit details
-
Copy full SHA for 335b6e4 - Browse repository at this point
Copy the full SHA 335b6e4View commit details -
Fix meter NaN spike + dB scale + add UI decay
LevelMeasurePipe's rolling +/- accumulation drifts to a tiny negative value during silence due to floating-point cancellation. sqrt(mean) then returned NaN, propagating through log10 into the UI which rendered the NaN as a max-pegged meter spike (very visible when pulling a send fader toward -inf). - Clamp mean to non-negative before sqrt. - Floor rms at 1e-6 so log10(0) doesn't produce -inf either. - Switch 10*log10(rms) -> 20*log10(rms): the previous formula was the intensity scale, not the amplitude scale. RMS peaks now read at the correct dBFS. UI: ShowManager runs a 50 ms QTimer that ramps each channel's displayed level toward -60 dBFS when no fresh meter packet has arrived for that channel in the last 100 ms. Without this the meter sticks at its last value forever when a stream stops (the engine simply stops sending updates rather than sending zeros). Decay rate: 1.2 dB/tick = ~24 dB/s; collapses from 0 dB to floor in ~2.5 s. Fast enough to read as "input went quiet," slow enough not to flicker on a single dropped packet.Configuration menu - View commit details
-
Copy full SHA for 4ffd69f - Browse repository at this point
Copy the full SHA 4ffd69fView commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff master...feature/dynamic-routing