Repository navigation
Conversation
Adds an RFCOMM backend for macOS so the CLI and GUI work there. A small Objective-C shim (compiled via the cc crate in build.rs) wraps IOBluetooth: listing connected paired devices, resolving SDP service UUIDs to RFCOMM channel ids, and opening/reading/writing channels. Notes on IOBluetooth behaviour that shaped the design: - On current macOS versions, IOBluetooth is backed by CoreBluetooth and delivers every RFCOMM delegate event on the main thread's run loop, regardless of which thread opened the channel. openRFCOMMChannelSync fails when called from a thread without a run loop, so the shim uses openRFCOMMChannelAsync and waits for rfcommChannelOpenComplete:status:. - The CLI therefore runs its tokio runtime on a secondary thread while the main thread spins a run loop (run_with_main_run_loop). The GUI already has one via winit. - IOBluetooth flattens single element SDP sequences, so ServiceClassIDList may be a bare UUID rather than an array. - The system sqlite on macOS is too old for the migrations, so rusqlite is built with the bundled feature like on Windows and Android. Tested with a Soundcore R50i (A3949): listing settings, reading battery and firmware info, and changing the equalizer preset.
afrijaldz
force-pushed
the
feat/macos-backend
branch
from
September 16, 2026 10:02
6e4f04c to
c2a5c08
Compare
This was referenced Sep 16, 2026
Contributor
|
Duplicates some functionality from #372. |
Author
|
You're right, #372 covers the same ground (and more) and was opened first — I hadn't seen it when I started this. I'm fine closing this one in favour of #372 once it's on track to merge. I'll leave it open for now only as a reference for a couple of behavioural differences I hit on macOS 15 / Apple Silicon, which I've noted over on #372. |
SeanathanVT
added a commit
to SeanathanVT/OpenSCQ30
that referenced
this pull request
Sep 17, 2026
writeSync:length: must not be called with more bytes than the channel's negotiated MTU, per IOBluetoothRFCOMMChannel's own documented contract. Our do_write sent the whole buffer in one call with no MTU check at all. Credit to afrijaldz's competing macOS PR (Oppzippy#374) for flagging this; splits do_write into an MTU-chunking outer loop plus a small per-chunk write_chunk helper carrying the existing not-open-yet retry logic unchanged. Co-Authored-By: Claude Sonnet 5 <[email protected]>
SeanathanVT
added a commit
to SeanathanVT/OpenSCQ30
that referenced
this pull request
Sep 17, 2026
writeSync:length: must not be called with more bytes than the channel's negotiated MTU, per IOBluetoothRFCOMMChannel's own documented contract. Our do_write sent the whole buffer in one call with no MTU check at all. Credit to afrijaldz's competing macOS PR (Oppzippy#374) for flagging this; splits do_write into an MTU-chunking outer loop plus a small per-chunk write_chunk helper carrying the existing not-open-yet retry logic unchanged. Co-Authored-By: Afrijal Dzuhri <[email protected]> Co-Authored-By: Claude Sonnet 5 <[email protected]>
Owner
|
Closing in favor of #372 |
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.
Summary
Adds a macOS RFCOMM connection backend built on Apple's IOBluetooth framework, so both the CLI and GUI work on macOS. Currently macOS falls through to the
nonebackend, and thedocs/build-macos.mdlink in the README is dead.lib/src/connection_backend/macos/with a small Objective-C shim (rfcomm.m, compiled bylib/build.rsvia thecccrate) and a RustRfcommBackend/RfcommConnectionimplementation over a C FFI.openscq30_lib::run_with_main_run_loop()for macOS, used by the CLI (see below).rusqlitewithbundledon macOS, matching Windows/Android — the system sqlite is too old for the migrations (json_valid()arity error).docs/build-macos.md.IOBluetooth behaviour worth knowing
Some things that were not obvious and shaped the design:
openRFCOMMChannelSyncfails when called from a thread that has no run loop, so the shim usesopenRFCOMMChannelAsyncand waits forrfcommChannelOpenComplete:status:on a semaphore.run_with_main_run_loop). This is macOS only; other platforms are unchanged.ServiceClassIDListcan be a bare UUID data element rather than an array.try_sendrather than blocking.@synchronizedguards the callback context against the channel being closed concurrently.Testing
Tested on macOS 15 (Apple Silicon) with a Soundcore R50i (A3949):
paired-devices add/device list-settings— all A3949 settings listedsetting -g serialNumber -g firmwareVersionLeft -g batteryLevelLeft -g batteryLevelRight— correct valuessetting -s presetEqualizerProfile=BassBooster -g volumeAdjustments— EQ bands change accordingly, and back toSoundcoreSignaturecargo fmtandcargo clippyare clean for the new code. I only have one device to test with, so testing on other models/macOS versions would be welcome.No CI or release packaging for macOS is included in this PR; happy to follow up on that separately if you'd like.