mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-10-03 09:05:17 -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
|
// Check if system audio capture is supported
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const supported = platform.audio.isSystemAudioSupported();
|
let isActive = true;
|
||||||
|
|
||||||
|
void platform.audio
|
||||||
|
.isSystemAudioSupported()
|
||||||
|
.then((supported) => {
|
||||||
|
if (isActive) {
|
||||||
setIsSupported(supported);
|
setIsSupported(supported);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (isActive) {
|
||||||
|
setIsSupported(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
isActive = false;
|
||||||
|
};
|
||||||
}, [platform]);
|
}, [platform]);
|
||||||
|
|
||||||
const startRecording = useCallback(async () => {
|
const startRecording = useCallback(async () => {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export interface AudioDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PlatformAudio {
|
export interface PlatformAudio {
|
||||||
isSystemAudioSupported(): boolean;
|
isSystemAudioSupported(): Promise<boolean>;
|
||||||
startSystemAudioCapture(maxDurationSecs: number): Promise<void>;
|
startSystemAudioCapture(maxDurationSecs: number): Promise<void>;
|
||||||
stopSystemAudioCapture(): Promise<Blob>;
|
stopSystemAudioCapture(): Promise<Blob>;
|
||||||
listOutputDevices(): Promise<AudioDevice[]>;
|
listOutputDevices(): Promise<AudioDevice[]>;
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ fn main() {
|
|||||||
// Link Swift runtime libraries for screencapturekit crate
|
// Link Swift runtime libraries for screencapturekit crate
|
||||||
#[cfg(target_os = "macos")]
|
#[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
|
// Add Swift runtime library paths to RPATH
|
||||||
println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/swift");
|
println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/swift");
|
||||||
println!("cargo:rustc-link-arg=-L/usr/lib/swift");
|
println!("cargo:rustc-link-arg=-L/usr/lib/swift");
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use screencapturekit::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
use std::process::Command;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
@@ -20,6 +21,10 @@ pub async fn start_capture(
|
|||||||
state: &AudioCaptureState,
|
state: &AudioCaptureState,
|
||||||
max_duration_secs: u32,
|
max_duration_secs: u32,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
if !is_supported() {
|
||||||
|
return Err("System audio capture requires macOS 12.3 or newer.".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
// Reset previous samples
|
// Reset previous samples
|
||||||
state.reset();
|
state.reset();
|
||||||
|
|
||||||
@@ -144,17 +149,22 @@ pub async fn stop_capture(state: &AudioCaptureState) -> Result<String, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_supported() -> bool {
|
pub fn is_supported() -> bool {
|
||||||
// ScreenCaptureKit requires macOS 12.3+
|
macos_version_at_least(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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> {
|
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';
|
import type { PlatformAudio, AudioDevice } from '@/platform/types';
|
||||||
|
|
||||||
export const tauriAudio: PlatformAudio = {
|
export const tauriAudio: PlatformAudio = {
|
||||||
isSystemAudioSupported(): boolean {
|
async isSystemAudioSupported(): Promise<boolean> {
|
||||||
// This will be checked dynamically via invoke
|
return await invoke<boolean>('is_system_audio_supported');
|
||||||
return true; // Tauri supports it, but actual support depends on platform
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async startSystemAudioCapture(maxDurationSecs: number): Promise<void> {
|
async startSystemAudioCapture(maxDurationSecs: number): Promise<void> {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { PlatformAudio, AudioDevice } from '@/platform/types';
|
import type { PlatformAudio, AudioDevice } from '@/platform/types';
|
||||||
|
|
||||||
export const webAudio: PlatformAudio = {
|
export const webAudio: PlatformAudio = {
|
||||||
isSystemAudioSupported(): boolean {
|
async isSystemAudioSupported(): Promise<boolean> {
|
||||||
return false; // System audio capture not supported in web
|
return false; // System audio capture not supported in web
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user