Skip to content

Port to macOS#2

Open
shamilatesoglu wants to merge 4 commits into
devfrom
nodos-1.4-macos
Open

Port to macOS#2
shamilatesoglu wants to merge 4 commits into
devfrom
nodos-1.4-macos

Conversation

@shamilatesoglu
Copy link
Copy Markdown
Member

macOS port of nos.audio.

Commits

  • 1.4 macOS port – baseline
  • System audio input: split into platform backends, add macOS ScreenCaptureKit backend, stabilize node status
  • Audio: fix SystemAudioInput activation, latency, and path-restart handling

Status

Draft.

…tureKit backend, stabilize node status

Splits SystemAudioInput's monolithic WASAPI-in-one-cpp into a platform-
agnostic interface (ISystemAudioCapture) with shared ring buffer / int24
packing in SystemAudioCaptureBase, and per-OS concrete backends:
  - Windows: WASAPI loopback (moved out of SystemAudioInput.cpp)
  - macOS 13+: ScreenCaptureKit via SCStream with capturesAudio = YES

The macOS backend runs all SCShareableContent / SCStream setup inside the
getShareableContentWithCompletionHandler block — smuggling the returned
SCShareableContent out across the block boundary crashed objc_msgSend in
the caller's frame on macOS 26, and the framework guarantees the object is
alive only inside the completion. Waits on ScreenCaptureKit completions
pump the main CFRunLoop instead of blocking on dispatch_semaphore; that
fixes both the lifetime crash and the main-queue deadlock that occurred
when libxpc delivered completions on dispatch_get_main_queue() while the
main thread was parked on the semaphore.

SystemAudioInput no longer pushes status messages from the Active pin
watcher or OnPathStart, and ExecuteNode no longer flips "Capturing audio"
vs "Audio capture is ready" every frame based on transient buffer state.
Three writers competing over one LastStatusMessage slot caused a visible
flap on the editor status line; ExecuteNode now owns the status and only
publishes on real state transitions. OnPathStart also stopped forcing a
NeedsReinitialize = true that destroyed and re-created the backend on every
scheduler-driven path restart; the SampleRate / ChannelCount watchers cover
actual format changes.
…dling

- Read Active pin directly in ExecuteNode instead of a watcher-backed
  mirror, so the node doesn't sit inert on graph load when the first
  ExecuteNode fires before the saved pin value has propagated.
- Drop OnPathStop's Capture->Stop() call: ScreenCaptureKit's Stop is a
  full stream teardown (not a pause), so across routine OnPathStop →
  OnPathStart cycles (graph load, downstream reconfig) the stream was
  left dead while the "ready" status lingered. Capture now stays alive
  until Active flips off or the node is destroyed.
- Add ISystemAudioCapture::DiscardBufferedSamples() and call it from
  OnPathStart to drop whatever queued up between Capture->Start() and
  the first consumer tick, so startup gap doesn't become permanent
  latency.
- Cap the residual ring buffer post-ReadSamples at ~100 ms so historical
  producer/consumer skew (startup, frame-drop stall, path-restart burst)
  resyncs to live instead of persisting as lag.
- Move the steady-state "Capturing system audio" status out of the init
  branch so it survives ClearNodeStatusMessages and reposts idempotently.
- Failure paths now write Active=false back to the pin via SetPinValue
  rather than toggling an internal mirror.
- Add NOS_MEMORY_FLAGS_DOWNLOAD to AudioPacketBuffer so VMA picks
  HOST_CACHED memory (the buffer is read on the host by the consumer
  node, which doesn't match the default SEQUENTIAL_WRITE hint).

AudioOscilloscope: guard the binning averager's divisor. When numSamples
is smaller than scopeTexSize * samplesPerBin, trailing bins have
startSample >= numSamples and the 0/0 produced NaN, poisoning
FrameHistory for the lifetime of the node context.

Rename k-prefixed constants to SNAKE_CASE per CodingConvention.md.
functiondiscoverykeys_devpkey.h references PROPERTYKEY, which mmdeviceapi.h
brings in. Include mmdeviceapi.h first so the property-key definitions see
a declared PROPERTYKEY.
@shamilatesoglu shamilatesoglu marked this pull request as ready for review April 24, 2026 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant