Repository navigation
fix(macos): macOS 15 fixes for feature/apple-macos-support (sqlite, RFCOMM open handshake) - #1
Merged
SeanathanVT merged 2 commits intoSep 17, 2026
Conversation
The system sqlite on macOS 15 is 3.43, which lacks the two-argument json_valid() used by the quick_preset migration, so the storage layer fails to open with "malformed database schema". Windows and Android already build with the bundled sqlite for the same reason.
…eband connection as a fallback On macOS 15 (Apple Silicon, Soundcore R50i) every other connect failed with kIOReturnNotOpen after exhausting the write retries. closeConnection is asynchronous, so calling openConnection/openRFCOMMChannelAsync right after it (which ensure_connected did whenever the device was already connected) raced the teardown and the channel never finished opening. When that failed the device was left disconnected, so the next attempt took the plain openConnection path and succeeded, hence the alternation. - Reuse an existing baseband connection instead of cycling it on every connect. This also removes the audible disconnect/reconnect and cuts connect time from ~3.5s to ~0.5s when the device is already connected. - Wait for rfcommChannelOpenComplete (with a timeout) before reporting the channel as open, rather than finding out on the first write. Only the callback is trusted: isOpen() flips to true a few hundred ms earlier and writes in that window fail. - Keep the baseband cycle as a fallback for when the open times out on a pre-existing connection (the stuck-channel case), and wait for isConnected() to go false before reopening so the cycle actually works. Tested on macOS 15.4 / M-series / Soundcore R50i: 15/15 back-to-back connects + EQ writes (4 of them recovered via the fallback), 10/10 with a 1s gap, EQ presets and button config verified to persist from a fresh process.
Owner
|
Thanks for this! good points all around. Sorry for missing this.. I have no macOS 15 host to test with. Verified that everything is still working on macOS 27 though. FWIW, I couldn't reproduce the "connect fails on every other attempt" behavior that you referenced, but these changes (unmodified) did not cause a regression on my macOS 27 host. I'm cool with keeping them as-is. Thanks again! |
SeanathanVT
merged commit Sep 17, 2026
6ddee0c
into
SeanathanVT:feature/apple-macos-support
5 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion to Oppzippy#372 — results of testing
404318deon macOS 15.4 / Apple Silicon / Soundcore R50i, with a fix on top. This is meant as a reference for the macOS 15 case, not a request to merge as-is: take whatever is useful, or just use it as evidence of what fails on 15. Details and numbers are in the Oppzippy#372 comment.What fails on macOS 15 with the branch as-is
malformed database schema (quick_preset) - wrong number of arguments to function json_valid(). macOS 15 ships sqlite 3.43; the 2-argjson_valid()needs 3.45+.kIOReturnNotOpenafter 49 write retries.closeConnectionis async andisConnected()stays true for ~0.5 s;ensure_connectedreopens inside that window and the channel never finishes opening. The failure leaves the device disconnected, so the next attempt takes the plainopenConnectionpath and works — hence the alternation.What this changes
lib/Cargo.toml: bundledrusqlitefor macOS (same as Windows/Android).rfcomm.rs:rfcommChannelOpenComplete(5 s timeout) before reporting the channel open. The delegate signals through a channel, so it doesn't matter which thread the callback lands on. Only the callback is trusted:isOpen()flips to true ~200 ms earlier and writes in that window fail with0xE00002E7.isConnected()to go false before reopening so the cycle actually works.Tested (macOS 15.4, M-series, R50i)
cargo check -p openscq30-guipassesNot verified: macOS 26/27
I can't test there. The one assumption that matters: your code comment says the open callback isn't dispatched until the first successful write on 26/27. On 15 it arrives ~0.5 s after
openRFCOMMChannelAsyncwith no write at all. If your observation holds on 26/27, the wait here would always time out and connects would fail there. If that's the case, a more conservative variant is easy: on timeout, log and proceed anyway (leaving the existing write-retry loop as the safety net) instead of failing — happy to push that instead if you'd prefer it.