mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-15 04:40:40 -07:00
fix: avoid ScreenCaptureKit launch crash on macOS 11 (#424)
Co-authored-by: txhno <[email protected]>
This commit is contained in:
@@ -26,8 +26,24 @@ export function useSystemAudioCapture({
|
||||
|
||||
// Check if system audio capture is supported
|
||||
useEffect(() => {
|
||||
const supported = platform.audio.isSystemAudioSupported();
|
||||
setIsSupported(supported);
|
||||
let isActive = true;
|
||||
|
||||
void platform.audio
|
||||
.isSystemAudioSupported()
|
||||
.then((supported) => {
|
||||
if (isActive) {
|
||||
setIsSupported(supported);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (isActive) {
|
||||
setIsSupported(false);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
isActive = false;
|
||||
};
|
||||
}, [platform]);
|
||||
|
||||
const startRecording = useCallback(async () => {
|
||||
|
||||
@@ -42,7 +42,7 @@ export interface AudioDevice {
|
||||
}
|
||||
|
||||
export interface PlatformAudio {
|
||||
isSystemAudioSupported(): boolean;
|
||||
isSystemAudioSupported(): Promise<boolean>;
|
||||
startSystemAudioCapture(maxDurationSecs: number): Promise<void>;
|
||||
stopSystemAudioCapture(): Promise<Blob>;
|
||||
listOutputDevices(): Promise<AudioDevice[]>;
|
||||
|
||||
@@ -5,6 +5,10 @@ fn main() {
|
||||
// Link Swift runtime libraries for screencapturekit crate
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
// ScreenCaptureKit does not exist on macOS 11, so weak-link it to
|
||||
// allow the app to launch and gate usage at runtime instead.
|
||||
println!("cargo:rustc-link-arg=-Wl,-weak_framework,ScreenCaptureKit");
|
||||
|
||||
// Add Swift runtime library paths to RPATH
|
||||
println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/swift");
|
||||
println!("cargo:rustc-link-arg=-L/usr/lib/swift");
|
||||
|
||||
@@ -13,6 +13,7 @@ use screencapturekit::{
|
||||
},
|
||||
};
|
||||
use std::io::Cursor;
|
||||
use std::process::Command;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
@@ -20,6 +21,10 @@ pub async fn start_capture(
|
||||
state: &AudioCaptureState,
|
||||
max_duration_secs: u32,
|
||||
) -> Result<(), String> {
|
||||
if !is_supported() {
|
||||
return Err("System audio capture requires macOS 12.3 or newer.".to_string());
|
||||
}
|
||||
|
||||
// Reset previous samples
|
||||
state.reset();
|
||||
|
||||
@@ -144,17 +149,22 @@ pub async fn stop_capture(state: &AudioCaptureState) -> Result<String, String> {
|
||||
}
|
||||
|
||||
pub fn is_supported() -> bool {
|
||||
// ScreenCaptureKit requires macOS 12.3+
|
||||
// Check if we're on a supported version
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
// Basic check - ScreenCaptureKit should be available on macOS 12.3+
|
||||
true
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
false
|
||||
}
|
||||
macos_version_at_least(12, 3)
|
||||
}
|
||||
|
||||
fn macos_version_at_least(required_major: u64, required_minor: u64) -> bool {
|
||||
let output = match Command::new("sw_vers").arg("-productVersion").output() {
|
||||
Ok(output) if output.status.success() => output,
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let version = String::from_utf8_lossy(&output.stdout);
|
||||
let mut parts = version.trim().split('.');
|
||||
|
||||
let major = parts.next().and_then(|part| part.parse::<u64>().ok()).unwrap_or(0);
|
||||
let minor = parts.next().and_then(|part| part.parse::<u64>().ok()).unwrap_or(0);
|
||||
|
||||
major > required_major || (major == required_major && minor >= required_minor)
|
||||
}
|
||||
|
||||
fn extract_audio_samples(sample_buffer: CMSampleBuffer) -> Result<Vec<f32>, String> {
|
||||
|
||||
@@ -2,9 +2,8 @@ import { invoke } from '@tauri-apps/api/core';
|
||||
import type { PlatformAudio, AudioDevice } from '@/platform/types';
|
||||
|
||||
export const tauriAudio: PlatformAudio = {
|
||||
isSystemAudioSupported(): boolean {
|
||||
// This will be checked dynamically via invoke
|
||||
return true; // Tauri supports it, but actual support depends on platform
|
||||
async isSystemAudioSupported(): Promise<boolean> {
|
||||
return await invoke<boolean>('is_system_audio_supported');
|
||||
},
|
||||
|
||||
async startSystemAudioCapture(maxDurationSecs: number): Promise<void> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { PlatformAudio, AudioDevice } from '@/platform/types';
|
||||
|
||||
export const webAudio: PlatformAudio = {
|
||||
isSystemAudioSupported(): boolean {
|
||||
async isSystemAudioSupported(): Promise<boolean> {
|
||||
return false; // System audio capture not supported in web
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user