Skip to content

AUv3: lay the subview out at the agreed size, and serialize audio unit creation - #565

Merged
defiantnerd merged 2 commits into
nextfrom
fix-553-auv3-view-and-bootstrap
Sep 15, 2026
Merged

defiantnerd merged 2 commits into
nextfrom
fix-553-auv3-view-and-bootstrap

Conversation

@defiantnerd

Copy link
Copy Markdown
Collaborator

Closes #553. The issue holds two unrelated defects in one file; they are two commits here.

1. The subview ignored adjust_size. After the container consulted adjust_size (added in #510), the layout pass still framed the subview from the raw container bounds — so an iPad rotation to landscape gave 1024x600 → adjust_size → 800x600 → plugin lays out at 800x600 → frame forced back to 1024x600, stretched. setGUISize:height: now writes the adjusted size back into the cached _guiWidth/_guiHeight (that cache was previously only updated by gui_request_resize, so it went stale after every host-driven resize), and the layout pass reads the agreed size back rather than using bounds. Side benefit: a non-resizable plugin, where setGUISize: is never called, also stops being stretched to the container.

2. Two AudioUnits could be created. _bootstrapAttempted guards re-entry on the main thread only — not against the host's factory call, which arrives on an XPC worker. Both could see audioUnit == nil and build one; the property overwrite then released the bootstrap AU whose GUI already existed, so dealloc reached terminate() without gui->destroy() (a CLAP contract violation, and a JUCE assert), while _tryCreateGUI ran against the survivor whose _guiCreated was false — a permanently empty editor. A new -createAudioUnitOnce:error: on the base class holds one mutex, re-checks, and runs the caller's build block; both generated-code producers now funnel through it instead of doing their own unlocked check-then-act. No second AU is built, so there is no loser to tear down.

Trade-off worth a reviewer's attention. Taking a real lock newly exposes one hazard: a plugin doing dispatch_sync to the main queue from inside clap_plugin->init() would deadlock against a main thread parked on that lock. That is a plugin bug (init is [main-thread]), but it was not reachable before. The alternative — try_lock with a placeholder-size fallback — would reintroduce the wrong-initial-size bug #510 fixed. There is no dispatch_sync anywhere in auv3_audiounit.mm, so nothing in the wrapper itself can deadlock here.

Scope. auv3_audiounit.h gains a five-line declaration so the generated subclasses can see the new method; the alternative was duplicating it as a category in both producers with no compiler cross-check.

Verification. Compile-verified under the Xcode generator: clap-first-distortion_auv3 and clap-first-distortion_auv3_standalone both build after each commit, and the regenerated generated_auv3_entrypoints.hxx in the build tree was confirmed to contain the new body, so the build-helper path is genuinely exercised. The iOS .hxx.in template is textually identical but was not compiled — no iOS toolchain here. Neither fix is runtime-tested: both need a physical iPad in AUM or GarageBand, and the race in commit 2 needs a slow-loading plugin to have any chance of reproducing.

The loadView bootstrap and the host's XPC factory call each built one, and the loser was released with its GUI still created.
@defiantnerd
defiantnerd force-pushed the fix-553-auv3-view-and-bootstrap branch from 6c51d39 to 0858e04 Compare September 15, 2026 04:45
@defiantnerd
defiantnerd merged commit 03252e3 into next Sep 15, 2026
28 checks passed
@defiantnerd
defiantnerd deleted the fix-553-auv3-view-and-bootstrap branch September 15, 2026 04:57
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