[package]
name = "fluxer_webrtc_sender"
version = "0.0.0"
edition = "2024"
license = "AGPL-3.0-or-later"
publish = false

[workspace]
resolver = "2"
exclude = [
    "vendor/tract-linalg-0.19.16",
    "vendor/tract-linalg-0.23.1",
]

[lib]
crate-type = ["cdylib", "rlib"]

[features]
# `publisher` pulls the LiveKit native SDK (libwebrtc). It is on by default for
# the real addon build, but `cargo test --no-default-features` builds only the
# pure YUV-conversion core so the unit tests run anywhere (no libwebrtc).
default = ["publisher"]
publisher = ["dep:livekit", "dep:tokio", "dep:futures-util"]
camera-native = ["dep:nokhwa"]
# Exposes pub re-exports of private camera-background hot-path internals so the
# criterion bench target can call them; never enabled for the shipped addon.
bench-internals = []

[dependencies]
napi = {version = "3.9.1", default-features = false, features = ["dyn-symbols", "napi8", "tokio_rt"]}
napi-derive = "3.5.6"
crossbeam-queue = "0.3"

# LiveKit native SDK (wraps libwebrtc). Optional / feature-gated. The exact
# version is resolved on the Windows build host (where the libwebrtc prebuilt
# links); pinned loosely here.
# Keep LiveKit's default features (default = ["tokio"] -> the runtime +
# signal-client-tokio) AND add a TLS backend for the signal WebSocket -- without
# one, connecting to a wss:// SFU fails with "TLS support not compiled in".
# rustls-tls-native-roots = pure-Rust TLS using the OS root store (no OpenSSL).
livekit = {version = "0.7", optional = true, features = ["rustls-tls-native-roots"]}
tokio = {version = "1", optional = true, features = ["rt-multi-thread", "sync", "macros", "time"]}
parking_lot = "0.12"
fluxer_screen_frame_bus = { path = "../screen-frame-bus" }
futures-core = "0.3"
# StreamExt::next() for draining inbound NativeAudioStream/NativeVideoStream.
futures-util = {version = "0.3", optional = true}
libloading = "0.9.0"
fluxer_desktop_native = { path = "../rust" }
image = {version = "0.25.10", default-features = false, features = ["jpeg", "png", "webp", "gif"]}
# System-camera capture for the native camera-publish path. Optional /
# feature-gated for the shipped desktop builds. `input-native` maps to V4L2 on
# Linux, AVFoundation on macOS, and Media Foundation on Windows.
# BUILD-HOST NOTE: `decoding` pulls `mozjpeg-sys`, which statically builds
# libjpeg and -- with its default `nasm_simd` -- needs NASM + a C compiler on the
# build host.
nokhwa = {version = "0.10", optional = true, default-features = false, features = ["input-native", "decoding"]}

# Person segmentation for camera background blur / replacement on platforms
# without a native segmentation API (Windows, Linux) and as the macOS fallback
# when Vision is unavailable. tract is a pure-Rust ONNX inference engine: no
# C++ runtime to link or ship per target, deterministic results, and the unit
# tests exercise the real model on any build host. It runs the bundled Apache-2.0
# MediaPipe Selfie Segmenter landscape model (models/, ~450 KB, embedded into the
# addon) in ~10 ms per 256x144 frame on a laptop core; an inference-cadence
# governor halves the rate on machines that miss the frame budget. Cost: ~40
# transitive crates, all pure Rust, compile-time only impact elsewhere.
tract-onnx = "0.23"

# DeepFilterNet3 noise suppression for the native device-microphone publish
# path, replacing the WebRTC-APM fallback when the renderer requests the
# deepFilter profile (parity with the web build's deepfilternet3-noise-filter
# WASM chain). The crates.io release (0.2.5, 2022) predates DFN3, so this pins
# the upstream git repo at the v0.5.6 release tag -- the combination the shipped
# deep-filter binaries were built from. `tract` + `default-model` run the
# bundled DFN3 ONNX models (~2 MB, embedded into the addon) on the same
# pure-Rust tract inference engine already used for person segmentation, albeit
# at tract 0.19 (deep_filter's tested series) alongside our 0.23 tree:
# compile-time cost only, no new native or C++ dependencies.
deep_filter = {git = "https://github.com/Rikorose/DeepFilterNet", rev = "978576aa8400552a4ce9730838c635aa30db5e61", default-features = false, features = ["tract", "default-model"]}
# deep_filter declares tract ^0.19.4, but newer releases in that semver range
# regress DFN3 model codegen (0.21.4 fails with "duplicate name .../Conv.bias"
# on the transposed convolutions). These renamed dependency keys exist solely
# to pin deep_filter's tract subtree to 0.19.16, the version in upstream's own
# v0.5.6 lockfile; tract's internal `=` pins drag tract-core/hir/data/linalg
# along. Never import these directly: the 0.23 `tract-onnx` entry above is the
# one the rest of this crate uses.
tract-onnx-deepfilter-pin = {package = "tract-onnx", version = "=0.19.16"}
tract-pulse-deepfilter-pin = {package = "tract-pulse", version = "=0.19.16"}
# Pinned to the 0.15 family to match deep_filter's public API surface
# (DfTract::process takes ndarray 0.15 ArrayView2 arguments).
ndarray = "0.15"

# macOS person segmentation for camera background blur / replacement. Vision's
# VNGeneratePersonSegmentationRequest produces the per-pixel person mask that the
# camera background transform composites with; without it the transform falls
# back to a fixed portrait ellipse. Pinned to the objc2 0.6 / framework 0.3
# family already used across fluxer_desktop/native, so no new dependency tree.
[target.'cfg(target_os = "macos")'.dependencies]
objc2 = "0.6"
objc2-foundation = {version = "0.3", features = ["NSArray", "NSDictionary", "NSError", "NSObject", "NSString"]}
objc2-vision = {version = "0.3", default-features = false, features = ["std", "VNRequest", "VNStatefulRequest", "VNGeneratePersonSegmentationRequest", "VNRequestHandler", "VNObservation", "VNTypes", "objc2-core-video", "objc2-core-foundation"]}
objc2-core-video = {version = "0.3", features = ["CVPixelBuffer", "CVImageBuffer", "CVBuffer", "CVReturn", "CVBase"]}
objc2-core-foundation = {version = "0.3", features = ["CFDictionary", "CFBase"]}

[build-dependencies]
napi-build = "2.3.2"

[dev-dependencies]
# Test-only (never linked into the shipped addon): parses the committed golden
# event fixtures so the renderer's (eventType, jsonPayload) parser contract is
# regression-locked offline, without a live SFU or a second identity.
serde_json = "1"
criterion = {version = "0.8", default-features = false, features = ["cargo_bench_support", "html_reports"]}

[[bench]]
name = "frame_bus"
harness = false
required-features = []

[[bench]]
name = "camera_background"
harness = false
required-features = ["bench-internals"]

[[bench]]
name = "deep_filter"
harness = false
required-features = ["bench-internals"]

[patch.crates-io]
libwebrtc = { path = "vendor/libwebrtc" }
webrtc-sys = { path = "vendor/webrtc-sys" }
tract-linalg-019 = { package = "tract-linalg", path = "vendor/tract-linalg-0.19.16" }
tract-linalg-023 = { package = "tract-linalg", path = "vendor/tract-linalg-0.23.1" }
