12 KiB
12 KiB
Implementation Plan
Implemented
- Repo-local persistence machinery.
- First architecture map.
- Example config for one video source plus two audio sources.
- Sender device discovery script.
- Sender launch script with dry-run mode and per-source FFmpeg commands.
- OBS receiver setup notes.
- Neighbor sender deployment under
C:\Meta\LocalCastBridge. - Madman's desktop start/stop launchers for the sender.
- Receiver OBS scene has
Neighbor PC - VideoandNeighbor PC - FocusriteMedia Sources. - Direct co-streamer loopback capture is now attempted with the repo WASAPI shim instead of Voicemeeter.
- Receiver OBS scene has
Neighbor PC - System Audioon SRT port5102. - Sender script uses
-nostdinand repo-root logs so desktop launchers stay alive and diagnostics land inC:\Meta\LocalCastBridge\logs. - Sender video config is
1920x1080for the interactive desktop. The1024x768SSH session size is not the streaming target. - Desktop
.cmdlaunchers delegate to PowerShell wrappers so paths with spaces and apostrophes are handled in one place. - Audio-field sidecar profile and tool:
config/audio-field.example.jsondeclares the actual distributed six-mic rig: two Kiyo mics, two PS Eye mics, local Focusrite shielded cardioid, neighbor Focusrite shotgun on the co-streamer, two local speakers, placeholder geometry, clock domains, capture policy, calibration sweep settings, and FOA AmbiX ACN/SN3D output.scripts/audio_field.pylists devices, validates shared or distributed profiles, checks local distributed sources, generates calibration sweeps, summarizes clock-domain sync requirements, preserves shared-input capture helpers, and encodes already aligned offline WAVs to FOA.audio_field/contains testable core modules for source buffering, bounded latency convergence, injectable capture/alignment/encoder/sink ports, and pipeline orchestration.docs/audio-field.mdmaps the audio pipeline and its invariants.
- Sensor-fusion render bridge:
localcast.sensor_fusion.calibration_spacesolves fixed-board ChArUco observations into camera poses in one common world frame.localcast.sensor_fusion.surface_featuresmatches cross-view features and triangulates calibrated surface tracks.localcast.sensor_fusion.render_bridgeemits render-frame packets with visual/audio timing metadata and Spout sender identity.localcast.sensor_fusion.cultcache_docsstores live visual state as typed CultCache MessagePack documents.localcast.sensor_fusion.spout_outputrenders render-frame packets into a GPU texture and publishes it as a named Spout sender for OBS.scripts/live_sensor_fusion.pywrites fused render frames intocalibration/runs/visual-state.msgpack.- The live visual producer writes a multi-LOD scene cache with source kind and priority. Real Leap frames are promoted as the highest-priority visual timing/spatial evidence; Leap fallback frames remain lower-priority diagnostics.
- Live clap calibration is wired into the visual producer. It keeps a rolling frame window from the Kiyo pair plus Leap, reads the live spatial audio frame for transient candidates, publishes
clap-events.msgpack, injects clap calibration markers into the render frame, and writes clap evidence into the LOD cache. Kiyo stereo owns the current rough 3D solve; Leap owns the best visual timing witness until its geometric model is calibrated. - Clap peaks now update a per-camera clock sync model. The point-cloud builder can sample camera history buffers at
oracle_time - camera_offsetinstead of using whichever frame arrived last. - The live visual producer now uses an explicit five-second spatiotemporal reservoir. RGB/Leap frame history expires from the newest shared sample, the multi-LOD cache only accepts evidence inside that same window, and
RenderFramePacket.source_time_min_ns/source_time_max_nsdeclares the reservoir slice being rendered. - Multi-LOD cells now carry first-pass material estimates: weighted albedo plus roughness/metallic hints derived from source evidence. Aquarium should treat this as relightable material evidence to refine, not as the final BRDF solve.
- The Spout/audio overlay boundary clamps stale visual packets to the current audio reservoir edge. If camera geometry ages out, it is dropped instead of being broadcast out of sync.
- Live fallback-only RGB/Leap mode exists for deadline operation when OpenCV/MSMF/DirectShow reads block longer than the five-second reservoir. It keeps the reservoir and OBS output alive while real camera capture is moved to nonblocking ingress.
localcast.sensor_fusion.chirp_poseconverts live phase-field delay meaning for Kiyo/PS Eye microphone sources into camera-body range constraints and per-camera pose-correction estimates. It can load camera-mic and speaker geometry from the audio-field profile, with the example profile used as the live fallback until measured local geometry exists.scripts/live_sensor_fusion.pyinjects those constraints ascamera-chirp:*andcamera-pose-correction:*render points pluschirp-camera-poseLOD evidence.scripts/stream_spout.pyruns the deadline Spout sender loop from the typed cache with typed and JSON heartbeat status.- The deadline Spout renderer has a named
kiyo-mid-deruvirtual camera preset: eye at the midpoint between the two Kiyo-class cameras and target on the co-streamer body volume. It also applies a renderer-owned point budget with pinned calibration/cross-modal constraints, stable high-confidence anchors, and frame-varying remainder samples so downstream TAA/supersampling can accumulate detail without forcing every source claim into every OBS frame. Its JSON heartbeat reports the prefix counts that survived the render budget. docs/obs-spout-streaming.mddocuments OBS setup and the Aquarium replacement boundary.docs/typed-visual-state.mddocuments the CultCache/CultNet visual boundary.
- OBS synchronized program surface:
scripts/setup_obs_synced_program.pyderives OBS-controllable stems from an aligned program audio timeline: host voice, co-streamer voice, ambient, transients, co-streamer loopback, and local loopback.scripts/capture_co_streamer_surfaces.pycaptures neighbor Focusrite and neighbor loopback with local loopback ground truth, estimates the late remote-family offset, and writes aligned co-streamer surfaces for the stem packer.scripts/wasapi-loopback-capture.ps1is the direct primary-playback loopback path. It must run in the neighbor's interactive console session; SSH-only capture sees the device but receives no render packets.- The tool creates/updates local OBS Media Sources for those stems and mutes/disables raw unsynchronized inputs.
- Strict mode disables every scene item except the synchronized LocalCastBridge program video and stem controls.
- Live phase-field meaning:
audio_field.phase_meaningextracts actionable delay, coherence, confidence, suppression, correction-energy, and active-probe need from internal phase/chirplet evidence.localcast.audio.phase_fieldis a typed CultCache document atcalibration/runs/audio-phase-field.msgpack.scripts/stream_phase_field.pypublishes the live meaning document from an aligned mic field plus known program/loopback reference without exposing raw phase bands as the renderer API.stream_phase_field.pyalso writesaudio-phase-field-status.json, which declares whether the phase estimator is running against replayed WAVs or closed-loop live capture. Current deadline mode is explicitwav-replaywith open-loop probe playback.audio_field.active_probewires low phase-field confidence intoActiveProbeOptimizer, emits bounded chirplet WAVs plusactive-probes.jsonl, and can play probes through the default output device.scripts/stream_live_audio_field.pyis the live local capture owner for the deadline rig. It publisheslocalcast.audio.mic_fieldandlocalcast.audio.phase_fieldfrom visible local WASAPI/PortAudio mics plus Scarlett loopback, reports missing rig channels as explicit placeholders, plays confidence probes through the selected Scarlett output, and resamples probe playback when the output device runs at 44.1 kHz while the field timeline remains 48 kHz.- Active probe artifacts are bounded: emitted chirps rotate through a fixed slot set and the manifest rotates at a byte cap. The calibration loop is allowed to be noisy; it is not allowed to become an unbounded filesystem leak.
scripts/start-live-audio-phase-field.ps1starts the live dense harmonic confidence loop with near-ultrasonic probes;scripts/stop-live-audio-phase-field.ps1stops the PID recorded inlogs/audio-phase-field.pid.
- Faust voice-separation boundary:
localcast.audio.mic_fieldpublishes aligned six-mic float32 blocks atcalibration/runs/audio-mic-field.msgpack.faust/localcast_voice_separation.dspis the first Aquarium-hosted graph surface for host voice, co-streamer voice, ambient, transient, and loopback stems.scripts/start-live-faust-mic-field.ps1starts the mic-field publisher for Aquarium/Faust.
Temporary
- Audio and video are separate SRT endpoints. This preserves OBS mixing authority but may need latency tuning.
- Audio defaults to AAC inside MPEG-TS for compatibility; test Opus later only if there is a concrete reason.
- Desktop capture uses
gdigrabfirst because it is broadly available.ddagrabis a candidate once the installed FFmpeg build is confirmed. - The scripts assume Windows sender and OBS receiver on the same LAN.
Next
- Open OBS and confirm the three
Neighbor PCsources load. - Start the sender from Madman's interactive desktop, not SSH.
- Smoke-test the video endpoint in OBS.
- Smoke-test the Focusrite endpoint in OBS.
- Smoke-test the system-loopback endpoint in OBS.
- Tune SRT latency and FFmpeg buffering for the local network.
- Decide whether a small OBS scene/source generator is worth adding.
- Reconsider plugin/fork only if standard OBS Media Source cannot preserve the required behavior.
- Create local
config/audio-field.json, confirm local Kiyo/PS Eye/Focusrite device matches, and confirm the neighbor Focusrite shotgun capture/transport path. - Replace placeholder mic/speaker geometry with measured world coordinates, then build the delay/SRO alignment stage that feeds the bounded field cache and emits aligned six-channel blocks before FOA encoding.
- Move the render-frame consumer into Aquarium Engine so dense brush/splat rendering replaces the deadline OpenGL point sink behind the same OBS Spout boundary.
- Capture fixed-board ChArUco observations for every camera, solve
config/sensor-fusion.json, and verify cross-view feature triangulation withscripts/triangulate_surface_features.py. - Replace synchronous OpenCV camera reads in the hot producer with nonblocking camera ingress that continuously fills the five-second reservoir, then promote real PS3 Eye/Kiyo/Leap samples over fallback-only mode.
- Replace the example speaker/camera-mic geometry used by
chirp_posewith measured localconfig/audio-field.jsoncoordinates, then let the common-space optimizer consume range residuals instead of only visualizing them. - Calibrate Leap as a geometric camera in the shared rig so the timing authority can also contribute direct 3D rays instead of only visual timing peaks.
- Fix the live Leap capture backend so actual Leap frames, not fallback frames, populate
leap-ground-truthcells in the multi-LOD cache. - Keep the neighbor loopback leg running through the scheduled interactive WASAPI capture path and use it as the timing witness once actual neighbor app audio is present.
- Let the co-streamer surface delay drive the shared presentation buffer horizon for audio stems, AmbiX, and remote video.
- Promote
scripts/stream_live_audio_field.pyfrom local deadline owner to the distributed owner by feeding it the neighbor Focusrite shotgun and neighbor loopback surfaces as synchronized live inputs instead of placeholders.