feat(core,clients): one rumble policy engine for every platform (rumble root fix D)
punktfunk-core client/rumble.rs: a per-connection policy engine consumes seq-gated wire
updates and emits EFFECTIVE actuator commands — re-emits on renewals (duration APIs stay
re-armed), self-silences at the v2 lease, a UNIFORM 1 s legacy-host staleness replacing the
per-platform zoo (Apple 1.6 s / Android 60 s / SDL 1.5 s / Deck 1 s), quirk-declared
actuator keepalives (Deck 40 ms + LSB dedupe-defeat jitter), and one stop per buzzing pad
on connection close. Per-pad mailbox semantics: a stalled embedder wakes to ONE current
command, and a stop can structurally never be the update an overflowing queue drops.
New API/ABI: NativeClient::{next_rumble_command,set_rumble_quirks} +
punktfunk_connection_next_rumble_cmd/_set_rumble_quirks (next_rumble/next_rumble2 stay for
un-migrated embedders; both consumers are fed). Migrations DELETE the platform forks:
pf-client-core loses RumbleState + the Deck keepalive loop + LEGACY_RUMBLE_CEILING_MS and
physically silences a slot at close; Android loses the 60 s legacy one-shot (backstop
repack, cancel-on-zero); Apple loses envelopeDeadline + sessionStaleSeconds + both tick
watchdogs (CoreHaptics realization untouched; mac xcframework rebuilt locally).
design/rumble-root-fix.md par. D. Engine 10/10 unit tests; core tests 176 Linux / 175
Windows + clippy -D warnings; swift build + RumbleTuningTests; Kotlin + android-native
compile green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+256
-190
@@ -197,6 +197,18 @@
|
||||
// own staleness heuristic for that update instead of a host-supplied deadline.
|
||||
#define PUNKTFUNK_RUMBLE_NO_TTL 4294967295
|
||||
|
||||
// `flags` bit for [`punktfunk_connection_set_rumble_quirks`]: alternate the low motor's LSB on
|
||||
// keepalive re-emits (imperceptible) so an SDL-class layer that no-ops identical values still
|
||||
// writes the device — the Steam Deck's dedupe-defeat.
|
||||
#define PUNKTFUNK_RUMBLE_QUIRK_DEDUP_JITTER 1
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// The uniform no-TTL-host staleness bound: a legacy host refreshes state every 500 ms, so two
|
||||
// missed refreshes = quiet host → silence. Replaces the per-platform zoo (1.6 s / 60 s / 1.5 s /
|
||||
// 1 s), and matches the ratio the Steam Deck ceiling shipped with.
|
||||
#define LEGACY_STALE_MS 1000
|
||||
#endif
|
||||
|
||||
// 16-byte AEAD authentication tag appended by GCM.
|
||||
#define TAG_LEN 16
|
||||
|
||||
@@ -328,11 +340,201 @@
|
||||
// `shard_payload` so `HEADER_LEN + shard_payload + CRYPTO_OVERHEAD ≤ MAX_DATAGRAM_BYTES`.
|
||||
#define MAX_DATAGRAM_BYTES 2048
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_caps`] bit: the client can decode a 10-bit (Main10) HEVC stream.
|
||||
#define VIDEO_CAP_10BIT 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_caps`] bit: the client can present BT.2020 PQ HDR10 (implies 10-bit).
|
||||
#define VIDEO_CAP_HDR 2
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_caps`] bit: the client can decode a full-chroma **4:4:4** HEVC stream (HEVC
|
||||
// Range Extensions / Rec.ITU-T H.265 `chroma_format_idc = 3`) AND its user turned 4:4:4 on (a
|
||||
// client-side setting, default OFF — the per-session policy switch). The host emits 4:4:4 ONLY
|
||||
// when this bit is set, the host allows it (`PUNKTFUNK_444`, default on), the codec is HEVC,
|
||||
// **and** the GPU/driver actually supports a 4:4:4 encode (probed) — otherwise the session stays
|
||||
// 4:2:0 and [`Welcome::chroma_format`] reflects the real resolved value. Independent of
|
||||
// 10-bit/HDR (4:4:4 is a chroma decision, bit depth is a depth decision; the two may combine
|
||||
// where the hardware allows).
|
||||
#define VIDEO_CAP_444 4
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_caps`] bit: the client consumes per-AU host-timing datagrams
|
||||
// ([`HOST_TIMING_MAGIC`], 0xCF) — the host's capture→send duration per frame, letting the client
|
||||
// split its `host+network` latency stage into `host` and `network`
|
||||
// (design/stats-unification.md Phase 2). The host emits 0xCF ONLY when this bit is set (an older
|
||||
// host ignores it and simply never sends any); a client that doesn't set it keeps the combined
|
||||
// stage. Purely observability — never changes what the host encodes.
|
||||
#define VIDEO_CAP_HOST_TIMING 8
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_caps`] bit: the client's reassembler keeps **speed-test probe filler in its own
|
||||
// frame-index space** (a second reassembly window keyed on the [`crate::packet::FLAG_PROBE`]
|
||||
// user-flag), so probe bursts no longer consume video `frame_index`es. Without this, a mid-session
|
||||
// speed test burns thousands of video indexes that are invisible to every client-side gap detector
|
||||
// (probe frames are filtered before the pump sees them) — the first real AU afterwards reads as a
|
||||
// phantom multi-thousand-frame loss (spurious freeze + a nonsense RFI). It also lets the host's
|
||||
// encode loop own the video numbering outright (the wire-index contract
|
||||
// [`crate::packet::Packetizer::packetize_each`] documents), which reference-frame invalidation
|
||||
// depends on. The host runs mid-session probe bursts ONLY against clients that set this bit — an
|
||||
// older client gets a declined (zeroed) [`ProbeResult`] instead of a measurement its single-window
|
||||
// reassembler would silently drop as stale.
|
||||
#define VIDEO_CAP_PROBE_SEQ 16
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Welcome::host_caps`] bit: the host applies [`InputKind::GamepadState`]
|
||||
// (crate::input::InputKind::GamepadState) snapshot events — full per-pad state with a reorder
|
||||
// sequence number. A capable client then sends gamepad state as snapshots (idempotent on the
|
||||
// lossy datagram plane, periodically refreshed) instead of the fragile per-transition
|
||||
// button/axis events; toward a host that doesn't set the bit it keeps the legacy events.
|
||||
#define HOST_CAP_GAMEPAD_STATE 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_codecs`] bit: the client can decode H.264 / AVC. The GPU-less **software**
|
||||
// encode path (openh264) emits H.264, so a client that wants to stream from a software host MUST
|
||||
// advertise this.
|
||||
#define CODEC_H264 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_codecs`] bit: the client can decode H.265 / HEVC — the default every existing
|
||||
// build produces and decodes (a peer that omits [`Hello::video_codecs`] is treated as HEVC-only).
|
||||
#define CODEC_HEVC 2
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_codecs`] bit: the client can decode AV1.
|
||||
#define CODEC_AV1 4
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_codecs`] bit: the client can decode **PyroWave** — the opt-in wired-LAN
|
||||
// intra-only wavelet codec (design/pyrowave-codec-plan.md; 100–400 Mbps class, 8-bit SDR,
|
||||
// every frame independently decodable). Deliberately **absent from [`resolve_codec`]'s
|
||||
// precedence ladder**: it is selected only when the client also names it
|
||||
// [`Hello::preferred_codec`] (or the host operator forces the advertisement mask) — a codec
|
||||
// that needs a wired-LAN bitrate must never win a negotiation just because both ends support
|
||||
// it. The bit means "PyroWave bitstream as of the punktfunk-vendored pin"
|
||||
// (`crates/pyrowave-sys/vendor/pyrowave/PUNKTFUNK-VENDOR.txt`): upstream has no bitstream
|
||||
// version field, so a vendored bump that changes the bitstream bumps the punktfunk protocol
|
||||
// version instead (plan §4.2).
|
||||
#define CODEC_PYROWAVE 8
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// HEVC `chroma_format_idc` for 4:2:0 — what every pre-4:4:4 build produced and the back-compat
|
||||
// default when a peer omits [`Welcome::chroma_format`].
|
||||
#define CHROMA_IDC_420 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// HEVC `chroma_format_idc` for full-chroma 4:4:4 (Range Extensions).
|
||||
#define CHROMA_IDC_444 3
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP colour-primaries code point: BT.709.
|
||||
#define ColorInfo_CP_BT709 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP colour-primaries code point: BT.2020.
|
||||
#define ColorInfo_CP_BT2020 9
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP transfer code point: BT.709.
|
||||
#define ColorInfo_TRC_BT709 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP transfer code point: PQ (SMPTE ST.2084).
|
||||
#define ColorInfo_TRC_PQ 16
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP transfer code point: HLG (ARIB STD-B67 / BT.2100).
|
||||
#define ColorInfo_TRC_HLG 18
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP matrix code point: BT.709.
|
||||
#define ColorInfo_MC_BT709 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP matrix code point: BT.2020 non-constant-luminance. (Never emit 10 / constant-luminance —
|
||||
// no client decodes it.)
|
||||
#define ColorInfo_MC_BT2020_NCL 9
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Rounds per batch — matches the connect-time [`clock_sync`].
|
||||
#define ClockResync_ROUNDS 8
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`Reconfigure`] (first byte after the magic).
|
||||
#define MSG_RECONFIGURE 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`Reconfigured`].
|
||||
#define MSG_RECONFIGURED 2
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`RequestKeyframe`].
|
||||
#define MSG_REQUEST_KEYFRAME 3
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`LossReport`].
|
||||
#define MSG_LOSS_REPORT 4
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`SetBitrate`].
|
||||
#define MSG_SET_BITRATE 5
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`BitrateChanged`].
|
||||
#define MSG_BITRATE_CHANGED 6
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`RfiRequest`].
|
||||
#define MSG_RFI_REQUEST 7
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`ProbeRequest`].
|
||||
#define MSG_PROBE_REQUEST 32
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`ProbeResult`].
|
||||
#define MSG_PROBE_RESULT 33
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`ClockProbe`].
|
||||
#define MSG_CLOCK_PROBE 48
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`ClockEcho`].
|
||||
#define MSG_CLOCK_ECHO 49
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Datagram wire tags. Video rides UDP; everything low-rate rides QUIC datagrams,
|
||||
// demultiplexed by the first byte: input = [`crate::input::INPUT_MAGIC`] (0xC8, client→host),
|
||||
@@ -421,53 +623,6 @@
|
||||
#define HOST_TIMING_MAGIC 207
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_caps`] bit: the client can decode a 10-bit (Main10) HEVC stream.
|
||||
#define VIDEO_CAP_10BIT 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_caps`] bit: the client can present BT.2020 PQ HDR10 (implies 10-bit).
|
||||
#define VIDEO_CAP_HDR 2
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_caps`] bit: the client can decode a full-chroma **4:4:4** HEVC stream (HEVC
|
||||
// Range Extensions / Rec.ITU-T H.265 `chroma_format_idc = 3`) AND its user turned 4:4:4 on (a
|
||||
// client-side setting, default OFF — the per-session policy switch). The host emits 4:4:4 ONLY
|
||||
// when this bit is set, the host allows it (`PUNKTFUNK_444`, default on), the codec is HEVC,
|
||||
// **and** the GPU/driver actually supports a 4:4:4 encode (probed) — otherwise the session stays
|
||||
// 4:2:0 and [`Welcome::chroma_format`] reflects the real resolved value. Independent of
|
||||
// 10-bit/HDR (4:4:4 is a chroma decision, bit depth is a depth decision; the two may combine
|
||||
// where the hardware allows).
|
||||
#define VIDEO_CAP_444 4
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_caps`] bit: the client consumes per-AU host-timing datagrams
|
||||
// ([`HOST_TIMING_MAGIC`], 0xCF) — the host's capture→send duration per frame, letting the client
|
||||
// split its `host+network` latency stage into `host` and `network`
|
||||
// (design/stats-unification.md Phase 2). The host emits 0xCF ONLY when this bit is set (an older
|
||||
// host ignores it and simply never sends any); a client that doesn't set it keeps the combined
|
||||
// stage. Purely observability — never changes what the host encodes.
|
||||
#define VIDEO_CAP_HOST_TIMING 8
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_caps`] bit: the client's reassembler keeps **speed-test probe filler in its own
|
||||
// frame-index space** (a second reassembly window keyed on the [`crate::packet::FLAG_PROBE`]
|
||||
// user-flag), so probe bursts no longer consume video `frame_index`es. Without this, a mid-session
|
||||
// speed test burns thousands of video indexes that are invisible to every client-side gap detector
|
||||
// (probe frames are filtered before the pump sees them) — the first real AU afterwards reads as a
|
||||
// phantom multi-thousand-frame loss (spurious freeze + a nonsense RFI). It also lets the host's
|
||||
// encode loop own the video numbering outright (the wire-index contract
|
||||
// [`crate::packet::Packetizer::packetize_each`] documents), which reference-frame invalidation
|
||||
// depends on. The host runs mid-session probe bursts ONLY against clients that set this bit — an
|
||||
// older client gets a declined (zeroed) [`ProbeResult`] instead of a measurement its single-window
|
||||
// reassembler would silently drop as stale.
|
||||
#define VIDEO_CAP_PROBE_SEQ 16
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// QUIC application error code a punktfunk/1 client closes the control connection with on a
|
||||
// **deliberate quit** (a user "stop", not a network drop). The host reads it off the connection's
|
||||
@@ -487,58 +642,6 @@
|
||||
#define APP_EXITED_CLOSE_CODE 82
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Welcome::host_caps`] bit: the host applies [`InputKind::GamepadState`]
|
||||
// (crate::input::InputKind::GamepadState) snapshot events — full per-pad state with a reorder
|
||||
// sequence number. A capable client then sends gamepad state as snapshots (idempotent on the
|
||||
// lossy datagram plane, periodically refreshed) instead of the fragile per-transition
|
||||
// button/axis events; toward a host that doesn't set the bit it keeps the legacy events.
|
||||
#define HOST_CAP_GAMEPAD_STATE 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_codecs`] bit: the client can decode H.264 / AVC. The GPU-less **software**
|
||||
// encode path (openh264) emits H.264, so a client that wants to stream from a software host MUST
|
||||
// advertise this.
|
||||
#define CODEC_H264 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_codecs`] bit: the client can decode H.265 / HEVC — the default every existing
|
||||
// build produces and decodes (a peer that omits [`Hello::video_codecs`] is treated as HEVC-only).
|
||||
#define CODEC_HEVC 2
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_codecs`] bit: the client can decode AV1.
|
||||
#define CODEC_AV1 4
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// [`Hello::video_codecs`] bit: the client can decode **PyroWave** — the opt-in wired-LAN
|
||||
// intra-only wavelet codec (design/pyrowave-codec-plan.md; 100–400 Mbps class, 8-bit SDR,
|
||||
// every frame independently decodable). Deliberately **absent from [`resolve_codec`]'s
|
||||
// precedence ladder**: it is selected only when the client also names it
|
||||
// [`Hello::preferred_codec`] (or the host operator forces the advertisement mask) — a codec
|
||||
// that needs a wired-LAN bitrate must never win a negotiation just because both ends support
|
||||
// it. The bit means "PyroWave bitstream as of the punktfunk-vendored pin"
|
||||
// (`crates/pyrowave-sys/vendor/pyrowave/PUNKTFUNK-VENDOR.txt`): upstream has no bitstream
|
||||
// version field, so a vendored bump that changes the bitstream bumps the punktfunk protocol
|
||||
// version instead (plan §4.2).
|
||||
#define CODEC_PYROWAVE 8
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// HEVC `chroma_format_idc` for 4:2:0 — what every pre-4:4:4 build produced and the back-compat
|
||||
// default when a peer omits [`Welcome::chroma_format`].
|
||||
#define CHROMA_IDC_420 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// HEVC `chroma_format_idc` for full-chroma 4:4:4 (Range Extensions).
|
||||
#define CHROMA_IDC_444 3
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Longest device name carried in a [`Hello`] (bytes of UTF-8; longer names are truncated on
|
||||
// encode, rejected on decode — a one-byte length prefix caps it at 255 anyway).
|
||||
@@ -551,61 +654,6 @@
|
||||
#define HELLO_LAUNCH_MAX 128
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`Reconfigure`] (first byte after the magic).
|
||||
#define MSG_RECONFIGURE 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`Reconfigured`].
|
||||
#define MSG_RECONFIGURED 2
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`RequestKeyframe`].
|
||||
#define MSG_REQUEST_KEYFRAME 3
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`LossReport`].
|
||||
#define MSG_LOSS_REPORT 4
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`SetBitrate`].
|
||||
#define MSG_SET_BITRATE 5
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`BitrateChanged`].
|
||||
#define MSG_BITRATE_CHANGED 6
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`RfiRequest`].
|
||||
#define MSG_RFI_REQUEST 7
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`ProbeRequest`].
|
||||
#define MSG_PROBE_REQUEST 32
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`ProbeResult`].
|
||||
#define MSG_PROBE_RESULT 33
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`ClockProbe`].
|
||||
#define MSG_CLOCK_PROBE 48
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`ClockEcho`].
|
||||
#define MSG_CLOCK_ECHO 49
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Type byte of [`PairRequest`].
|
||||
#define MSG_PAIR_REQUEST 16
|
||||
@@ -626,42 +674,6 @@
|
||||
#define MSG_PAIR_RESULT 19
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP colour-primaries code point: BT.709.
|
||||
#define ColorInfo_CP_BT709 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP colour-primaries code point: BT.2020.
|
||||
#define ColorInfo_CP_BT2020 9
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP transfer code point: BT.709.
|
||||
#define ColorInfo_TRC_BT709 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP transfer code point: PQ (SMPTE ST.2084).
|
||||
#define ColorInfo_TRC_PQ 16
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP transfer code point: HLG (ARIB STD-B67 / BT.2100).
|
||||
#define ColorInfo_TRC_HLG 18
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP matrix code point: BT.709.
|
||||
#define ColorInfo_MC_BT709 1
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// CICP matrix code point: BT.2020 non-constant-luminance. (Never emit 10 / constant-luminance —
|
||||
// no client decodes it.)
|
||||
#define ColorInfo_MC_BT2020_NCL 9
|
||||
#endif
|
||||
|
||||
// Consecutive no-output AUs that force a keyframe request. ~50 ms at 60 Hz — long enough not to fire
|
||||
// on a one-frame decoder hiccup, short enough that a lost initial IDR (or a mid-GOP join) unfreezes
|
||||
// almost immediately instead of never.
|
||||
@@ -717,6 +729,12 @@
|
||||
// The client's wire (protocol) version does not match the host's — one side needs updating.
|
||||
#define WIRE_VERSION_CLOSE_CODE 103
|
||||
|
||||
// Minimum supported multiplier (renders under native, upscaled on present).
|
||||
#define MIN_SCALE 0.5
|
||||
|
||||
// Maximum supported multiplier (supersamples, clamped to the codec ceiling per axis).
|
||||
#define MAX_SCALE 4.0
|
||||
|
||||
// Stable C ABI status codes. `Ok` is 0; all errors are negative so callers can
|
||||
// test `rc < 0`. Do not renumber existing variants — only append.
|
||||
enum PunktfunkStatus
|
||||
@@ -1120,6 +1138,10 @@ typedef struct {
|
||||
|
||||
|
||||
|
||||
// The multipliers a picker offers. `1.0` (Native) is the default; the rest are the round stops
|
||||
// users reason about. Shared so every client's list stays identical.
|
||||
#define PRESETS { 0.5, 0.67, 0.75, 1.0, 1.25, 1.5, 2.0, 3.0, 4.0, }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
@@ -1600,6 +1622,50 @@ PunktfunkStatus punktfunk_connection_next_rumble2(PunktfunkConnection *c,
|
||||
uint32_t timeout_ms);
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Pull the next EFFECTIVE rumble command from the shared policy engine — the uniform replacement
|
||||
// for per-platform rumble policy. Unlike [`punktfunk_connection_next_rumble2`], the caller never
|
||||
// sees a TTL and never owns a deadline: the engine emits the level on every wire update (renewals
|
||||
// re-arm duration-parameterized APIs), an explicit zero at lease expiry / legacy-host staleness
|
||||
// (a uniform 1 s) / connection close, and any keepalives declared via
|
||||
// [`punktfunk_connection_set_rumble_quirks`]. Apply commands verbatim: `(0, 0)` = stop now;
|
||||
// non-zero = run at this level, with `*backstop_ms` as the safety-net duration for platform APIs
|
||||
// that take one (explicit-stop APIs ignore it; it is `0` on stop commands).
|
||||
// [`PunktfunkStatus::NoFrame`] on timeout; [`PunktfunkStatus::Closed`] once the session ended AND
|
||||
// every close-drain stop was delivered — silence all actuators on it.
|
||||
//
|
||||
// An embedder uses EITHER this or `next_rumble`/`next_rumble2` for a connection's lifetime,
|
||||
// never both (they consume the same wire plane).
|
||||
//
|
||||
// # Safety
|
||||
// `c` is a valid connection handle; out pointers are writable (NULLs are skipped). At most one
|
||||
// thread pulls rumble — it may run concurrently with the video/audio pullers.
|
||||
PunktfunkStatus punktfunk_connection_next_rumble_cmd(PunktfunkConnection *c,
|
||||
uint16_t *pad,
|
||||
uint16_t *low,
|
||||
uint16_t *high,
|
||||
uint32_t *backstop_ms,
|
||||
uint32_t timeout_ms);
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Declare a physical actuator's quirks for wire pad `pad` — how a platform parameterizes the
|
||||
// shared rumble policy engine instead of forking it (typically called at controller attach).
|
||||
// `keepalive_ms`: re-emit an unchanged non-zero level at this cadence for actuators whose
|
||||
// hardware output decays between wire renewals (Steam Deck ≈ 40, DualSense-over-BT raw HID
|
||||
// ≈ 900); `0` = none. `min_pulse_ms`: floor for `backstop_ms` on non-zero commands. `flags`:
|
||||
// [`PUNKTFUNK_RUMBLE_QUIRK_DEDUP_JITTER`]. All-zero (the initial state) describes a well-behaved
|
||||
// actuator.
|
||||
//
|
||||
// # Safety
|
||||
// `c` is a valid connection handle. Callable from any thread.
|
||||
PunktfunkStatus punktfunk_connection_set_rumble_quirks(PunktfunkConnection *c,
|
||||
uint16_t pad,
|
||||
uint16_t keepalive_ms,
|
||||
uint16_t min_pulse_ms,
|
||||
uint32_t flags);
|
||||
#endif
|
||||
|
||||
#if defined(PUNKTFUNK_FEATURE_QUIC)
|
||||
// Pull the next DualSense HID-output feedback event (lightbar / player LEDs / adaptive trigger)
|
||||
// the host's virtual pad received from a game, into `*out`. [`PunktfunkStatus::NoFrame`] on
|
||||
|
||||
Reference in New Issue
Block a user