Complete managed macOS platform bring-up
.NET port / test (macos-latest) (push) Canceled after 0s
.NET port / test (ubuntu-24.04) (push) Canceled after 0s
.NET port / test (windows-latest) (push) Canceled after 0s
.NET port / apple-client (push) Canceled after 0s
.NET port / cpp-conformance (push) Canceled after 0s

This commit is contained in:
2026-09-18 18:51:53 +02:00
parent ab460ae12b
commit 310c0f09dd
21 changed files with 421 additions and 83 deletions
+10 -6
View File
@@ -1,16 +1,20 @@
# Managed Apple clients
`VoiceCat.Mac` is the native AppKit C# port. It targets `net10.0-macos` and references the same `VoiceCat.Core` and `VoiceCat.Audio` assemblies used by the Windows client and managed CLI.
`VoiceCat.Mac` is the native AppKit C# port. It targets `net10.0-macos27.0` and references the same `VoiceCat.Core` and `VoiceCat.Audio` assemblies used by the Windows client and managed CLI. The explicit platform version selects Microsoft's Xcode 27 preview bindings; the deployed app still supports macOS 14 and later.
The current checkpoint is a functional client: AppKit launch/menu lifecycle, saved server profiles, guest and account authentication, explicit TOFU approval (including changed-key warning), protected-channel password prompts, channel selection, user roster, channel and private text, voice subscription, managed microphone-stream lifecycle, default-device Core Audio capture/playback, disconnect reporting, native accessibility labels, sandbox/network/audio entitlements, and deterministic disposal. Profiles save the host, port, authentication mode, username or guest nickname. An account password can be remembered as a macOS Keychain generic-password item only after successful authentication; it is never written to profile JSON and is removed when remembering is disabled or the profile is deleted. Capture is converted to interleaved 48 kHz int16 PCM through `AVAudioConverter`; playback uses an `AVAudioSourceNode` and the shared bounded `PcmRing`, so its render callback does not allocate, lock, or block. It does not yet replace the Swift release. Non-default device selection, moderation sheets, settings, ScreenCaptureKit sharing, VoiceOver verification, signing and notarization remain.
The current checkpoint is a functional client: AppKit launch/menu lifecycle, saved server profiles, guest and account authentication, explicit TOFU approval (including changed-key warning), protected-channel password prompts, channel selection, user roster, channel and private text, voice subscription, managed microphone-stream lifecycle, selectable Core Audio input/output devices, disconnect reporting, native accessibility labels, sandbox/network/audio entitlements, and deterministic disposal. Profiles save the host, port, authentication mode, username or guest nickname. An account password can be remembered as a macOS Keychain generic-password item only after successful authentication; it is never written to profile JSON and is removed when remembering is disabled or the profile is deleted. Joining voice requests microphone authorization explicitly. Capture is converted to interleaved 48 kHz int16 PCM through `AVAudioConverter`; playback converts the shared bounded `PcmRing` into Core Audio's native planar Float32 layout inside an allocation-free, non-blocking `AVAudioSourceNode` callback. It does not yet replace the Swift release. Moderation sheets, settings, ScreenCaptureKit sharing, VoiceOver verification, signing and notarization remain.
Build on Apple Silicon macOS 15.6+ with Xcode 26 and the .NET 10 macOS workload:
Build on Apple Silicon macOS 27 with Xcode 27, .NET SDK 10.0.401 and workload set 10.0.401. Homebrew `protobuf` supplies a native arm64 `protoc`; the current `Grpc.Tools` package contains only an x64 macOS compiler.
```bash
dotnet workload install macos
pwsh ./dotnet/build-native.ps1
sudo dotnet workload install macos ios --version 10.0.401
brew install protobuf # if /opt/homebrew/bin/protoc is not already present
cmake -S dotnet/native -B dotnet/artifacts/native-build -DCMAKE_BUILD_TYPE=Release -DVOICECAT_DOTNET_RID=osx-arm64
cmake --build dotnet/artifacts/native-build --config Release --target voicecat_media --parallel 2
cmake --install dotnet/artifacts/native-build --config Release --component DotnetMedia --prefix dotnet/artifacts/native
dotnet restore clients/apple/dotnet/VoiceCat.Apple.slnx
dotnet build clients/apple/dotnet/VoiceCat.Apple.slnx -c Debug
open clients/apple/dotnet/VoiceCat.Mac/bin/Debug/net10.0-macos27.0/osx-arm64/VoiceCat.app
```
The native build stages an `osx-arm64` `libvoicecat_media.dylib`; that shim contains only Opus/RNNoise. The AppKit and AVFoundation calls are also compiled against Microsoft's current macOS reference assembly during development, but only a macOS host can link, launch, grant microphone access and verify live devices. The macOS CI build and manual listen test are required release gates.
The native build stages an `osx-arm64` `libvoicecat_media.dylib`; that shim contains only Opus/RNNoise. Debug builds deliberately omit hardened runtime so an ad-hoc-signed local app can load the separately ad-hoc-signed .NET runtime libraries without an Apple Development identity. Release builds retain hardened runtime for Developer ID signing and notarization. Only a macOS host can link, launch, grant microphone access and verify live devices. Final audio quality is validated with real multi-human calls after the feature surface is complete; a synthetic ten-minute sine-wave listen is deliberately not a release gate.