feat(host/windows): host→client Opus audio — vendored libopus on MSVC
The `m3` audio_thread (desktop capture → Opus 48 kHz stereo 5 ms CBR → AUDIO_MAGIC datagrams) now runs on Windows, fed by the WASAPI loopback capturer. The `opus` crate vendors libopus via `audiopus_sys` + cmake (no system lib / vcpkg), so it builds on MSVC — moved into a `cfg(any(linux, windows))` deps table and widened the audio_thread cfg to match (the stub now only covers other targets, e.g. macOS). Build note: CMake 4 rejects libopus's old `cmake_minimum_required`; set `CMAKE_POLICY_VERSION_MINIMUM=3.5` when building the host on Windows. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,12 @@ utoipa-scalar = { version = "0.3", features = ["axum"] }
|
|||||||
tower = { version = "0.5", features = ["util"] }
|
tower = { version = "0.5", features = ["util"] }
|
||||||
http-body-util = "0.1"
|
http-body-util = "0.1"
|
||||||
|
|
||||||
|
# Opus stereo encode for the host->client audio plane. The `opus` crate vendors libopus via
|
||||||
|
# `audiopus_sys` (cmake-built from source — no system lib, no vcpkg), so it builds on Windows MSVC
|
||||||
|
# too (needs CMake + NASM, both on the box). Both platforms that have an audio-capture backend.
|
||||||
|
[target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies]
|
||||||
|
opus = "0.3"
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
# `screencast` gates the ScreenCast portal module; `remote_desktop` adds the RemoteDesktop
|
# `screencast` gates the ScreenCast portal module; `remote_desktop` adds the RemoteDesktop
|
||||||
# portal we use for libei input on KWin/GNOME; `tokio` is the default runtime.
|
# portal we use for libei input on KWin/GNOME; `tokio` is the default runtime.
|
||||||
@@ -81,8 +87,6 @@ wayland-backend = "0.3"
|
|||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
# Builds/validates the xkb keymap uploaded to the virtual keyboard + tracks modifier state.
|
# Builds/validates the xkb keymap uploaded to the virtual keyboard + tracks modifier state.
|
||||||
xkbcommon = "0.8"
|
xkbcommon = "0.8"
|
||||||
# Opus encode for the GameStream audio stream (links system libopus).
|
|
||||||
opus = "0.3"
|
|
||||||
# The safe `opus` crate is stereo-only; surround (5.1/7.1) needs the libopus *multistream*
|
# The safe `opus` crate is stereo-only; surround (5.1/7.1) needs the libopus *multistream*
|
||||||
# encoder (`opus_multistream_encoder_*`). `audiopus_sys` is the sys layer `opus` already
|
# encoder (`opus_multistream_encoder_*`). `audiopus_sys` is the sys layer `opus` already
|
||||||
# vendors (same libopus link), so this adds bindings, not a second copy of the library.
|
# vendors (same libopus link), so this adds bindings, not a second copy of the library.
|
||||||
|
|||||||
@@ -1340,7 +1340,7 @@ fn input_thread(
|
|||||||
/// The audio thread: desktop capture → Opus (48 kHz stereo, 5 ms, CBR — same tuning as the
|
/// The audio thread: desktop capture → Opus (48 kHz stereo, 5 ms, CBR — same tuning as the
|
||||||
/// GameStream path) → `AUDIO_MAGIC` datagrams. QUIC already encrypts; no extra layer.
|
/// GameStream path) → `AUDIO_MAGIC` datagrams. QUIC already encrypts; no extra layer.
|
||||||
/// The capturer comes from (and returns to) the persistent slot — see [`AudioCapSlot`].
|
/// The capturer comes from (and returns to) the persistent slot — see [`AudioCapSlot`].
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
fn audio_thread(conn: quinn::Connection, stop: Arc<AtomicBool>, audio_cap: AudioCapSlot) {
|
fn audio_thread(conn: quinn::Connection, stop: Arc<AtomicBool>, audio_cap: AudioCapSlot) {
|
||||||
use crate::audio::{CHANNELS, SAMPLE_RATE};
|
use crate::audio::{CHANNELS, SAMPLE_RATE};
|
||||||
const FRAME_MS: usize = 5;
|
const FRAME_MS: usize = 5;
|
||||||
@@ -1415,11 +1415,9 @@ fn audio_thread(conn: quinn::Connection, stop: Arc<AtomicBool>, audio_cap: Audio
|
|||||||
|
|
||||||
/// Stub — punktfunk/1 audio needs Linux (PipeWire capture + libopus); non-Linux dev builds
|
/// Stub — punktfunk/1 audio needs Linux (PipeWire capture + libopus); non-Linux dev builds
|
||||||
/// run sessions without it, same as when the capturer fails to open.
|
/// run sessions without it, same as when the capturer fails to open.
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(any(target_os = "linux", target_os = "windows")))]
|
||||||
fn audio_thread(_conn: quinn::Connection, _stop: Arc<AtomicBool>, _audio_cap: AudioCapSlot) {
|
fn audio_thread(_conn: quinn::Connection, _stop: Arc<AtomicBool>, _audio_cap: AudioCapSlot) {
|
||||||
tracing::warn!(
|
tracing::warn!("punktfunk/1 audio requires Linux or Windows — session continues without it");
|
||||||
"punktfunk/1 audio requires Linux (PipeWire + libopus) — session continues without it"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn synthetic_stream(
|
fn synthetic_stream(
|
||||||
|
|||||||
Reference in New Issue
Block a user