/* punktfunk-core C ABI — see crates/punktfunk-core/src/abi.rs */ #ifndef PUNKTFUNK_CORE_H #define PUNKTFUNK_CORE_H #pragma once /* Generated by cbindgen from punktfunk-core. Do not edit by hand. */ #include #include #include #include // Bump on any breaking change to the [C ABI](crate::abi). Mirrors // `punktfunk_abi_version()` and is checked by clients before use. // // v2: `punktfunk_connect` gained `client_cert_pem`/`client_key_pem` (pairing identities); // added `punktfunk_pair` / `punktfunk_generate_identity` / `punktfunk_connection_request_mode`. #define ABI_VERSION 2 // `PunktfunkHidOutput::kind` — lightbar RGB (`r`/`g`/`b` valid). #define PUNKTFUNK_HIDOUT_LED 1 // `PunktfunkHidOutput::kind` — player-indicator LEDs (`player_bits` valid, low 5 bits). #define PUNKTFUNK_HIDOUT_PLAYER_LEDS 2 // `PunktfunkHidOutput::kind` — one adaptive-trigger effect (`which` + `effect`/`effect_len` valid). #define PUNKTFUNK_HIDOUT_TRIGGER 3 // Capacity of `PunktfunkHidOutput::effect` (the DualSense trigger parameter block). #define PUNKTFUNK_HID_EFFECT_MAX 11 // `PunktfunkRichInput::kind` — a touchpad contact (`finger`/`active`/`x`/`y` valid). #define PUNKTFUNK_RICH_TOUCHPAD 1 // `PunktfunkRichInput::kind` — a motion sample (`gyro`/`accel` valid). #define PUNKTFUNK_RICH_MOTION 2 // Compositor preference for [`punktfunk_connect_ex`] (`compositor` arg). `AUTO` lets the host // pick (auto-detect from its running desktop); a concrete value is honored only if that backend // is available on the host right now, else the host falls back to auto-detect. The resolved // choice is reported back over the protocol (see `punktfunk/1` `Welcome`). #define PUNKTFUNK_COMPOSITOR_AUTO 0 // KWin / KDE Plasma. #define PUNKTFUNK_COMPOSITOR_KWIN 1 // wlroots (Sway / Hyprland). #define PUNKTFUNK_COMPOSITOR_WLROOTS 2 // Mutter / GNOME. #define PUNKTFUNK_COMPOSITOR_MUTTER 3 // gamescope (spawned nested). #define PUNKTFUNK_COMPOSITOR_GAMESCOPE 4 // Gamepad-backend preference for [`punktfunk_connect_ex2`] (`gamepad` arg): which virtual pad // the host creates for this session's controllers. Precedence host-side: an explicit client // choice > the host's `PUNKTFUNK_GAMEPAD` env var > X-Box 360. `AUTO` (or any unrecognized // value) = host decides. The resolved choice is echoed over the protocol (`Welcome`) and // readable via [`punktfunk_connection_gamepad`]. #define PUNKTFUNK_GAMEPAD_AUTO 0 // uinput X-Box 360 pad (the universal default — every game speaks XInput). #define PUNKTFUNK_GAMEPAD_XBOX360 1 // UHID DualSense (kernel `hid-playstation`): adaptive triggers, lightbar, touchpad, motion — // feedback arrives on the HID-output plane ([`punktfunk_connection_next_hidout`]). Honored // only where available (Linux hosts); otherwise the host falls back to X-Box 360. #define PUNKTFUNK_GAMEPAD_DUALSENSE 2 // 16-byte AEAD authentication tag appended by GCM. #define TAG_LEN 16 // Wire tag distinguishing an input datagram from a video packet. #define INPUT_MAGIC 200 // Fixed serialized size of an [`InputEvent`] on the wire (tag + fields). #define INPUT_WIRE_LEN (((((1 + 1) + 4) + 4) + 4) + 4) #define PUNKTFUNK_BTN_DPAD_UP 1 #define PUNKTFUNK_BTN_DPAD_DOWN 2 #define PUNKTFUNK_BTN_DPAD_LEFT 4 #define PUNKTFUNK_BTN_DPAD_RIGHT 8 #define PUNKTFUNK_BTN_START 16 #define PUNKTFUNK_BTN_BACK 32 #define PUNKTFUNK_BTN_LS_CLICK 64 #define PUNKTFUNK_BTN_RS_CLICK 128 #define PUNKTFUNK_BTN_LB 256 #define PUNKTFUNK_BTN_RB 512 #define PUNKTFUNK_BTN_GUIDE 1024 #define PUNKTFUNK_BTN_A 4096 #define PUNKTFUNK_BTN_B 8192 #define PUNKTFUNK_BTN_X 16384 #define PUNKTFUNK_BTN_Y 32768 // DualSense touchpad click. Moonlight's extended-button position (`buttonFlags2` // merges in at `<< 16`, see `gamestream/gamepad.rs`), so GameStream clients land on // the same bit. Only the DualSense backend renders it; the xpad has no such button. #define PUNKTFUNK_BTN_TOUCHPAD 1048576 // Axis ids for `InputKind::GamepadAxis`. #define PUNKTFUNK_AXIS_LS_X 0 #define PUNKTFUNK_AXIS_LS_Y 1 #define PUNKTFUNK_AXIS_RS_X 2 #define PUNKTFUNK_AXIS_RS_Y 3 // Triggers: value range 0..255. #define PUNKTFUNK_AXIS_LT 4 #define PUNKTFUNK_AXIS_RT 5 // Identifies a punktfunk video packet (vs. an input datagram, see [`crate::input`]). #define PUNKTFUNK_MAGIC 201 #define FLAG_PIC 1 #define FLAG_EOF 2 #define FLAG_SOF 4 // Bandwidth-probe filler, not decodable video: a [`crate::quic::ProbeRequest`] speed test makes // the host burst access units carrying this flag so the client measures throughput/loss without // feeding them to the decoder. Punktfunk/1 only (GameStream never sets it). #define FLAG_PROBE 8 // Largest UDP datagram the core will send or accept. `Config::validate` bounds // `shard_payload` so `HEADER_LEN + shard_payload + CRYPTO_OVERHEAD ≤ MAX_DATAGRAM_BYTES`. #define MAX_DATAGRAM_BYTES 2048 #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). #define HELLO_NAME_MAX 64 #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 [`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 #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Type byte of [`PairChallenge`]. #define MSG_PAIR_CHALLENGE 17 #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Type byte of [`PairProof`]. #define MSG_PAIR_PROOF 18 #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Type byte of [`PairResult`]. #define MSG_PAIR_RESULT 19 #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), // audio = [`AUDIO_MAGIC`] (0xC9, host→client), rumble = [`RUMBLE_MAGIC`] (0xCA, host→client), // mic = [`MIC_MAGIC`] (0xCB, client→host), rich-input = [`RICH_INPUT_MAGIC`] (0xCC, client→host), // HID-output = [`HIDOUT_MAGIC`] (0xCD, host→client). #define PUNKTFUNK_AUDIO_MAGIC 201 #endif #if defined(PUNKTFUNK_FEATURE_QUIC) #define PUNKTFUNK_RUMBLE_MAGIC 202 #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Microphone uplink: the client's mic, Opus-encoded, client → host (the inverse of // [`AUDIO_MAGIC`]). The host feeds it into a virtual PipeWire source so its apps can record it. #define MIC_MAGIC 203 #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Rich client→host input: events too big for the fixed 18-byte [`InputEvent`] // (crate::input::InputEvent) — the DualSense touchpad and motion sensors. Variable-length, // kind-tagged (see [`RichInput`]). #define RICH_INPUT_MAGIC 204 #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // HID output, host → client: DualSense feedback a game wrote to the host's virtual controller // (lightbar, player LEDs, adaptive triggers) — the rich analog of [`RUMBLE_MAGIC`]. See // [`HidOutput`]. #define HIDOUT_MAGIC 205 #endif // 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 #if defined(__cplusplus) || __STDC_VERSION__ >= 202311L : int32_t #endif // defined(__cplusplus) || __STDC_VERSION__ >= 202311L { PUNKTFUNK_STATUS_OK = 0, PUNKTFUNK_STATUS_INVALID_ARG = -1, PUNKTFUNK_STATUS_FEC = -2, PUNKTFUNK_STATUS_CRYPTO = -3, PUNKTFUNK_STATUS_BAD_PACKET = -4, PUNKTFUNK_STATUS_NO_FRAME = -5, PUNKTFUNK_STATUS_UNSUPPORTED = -6, PUNKTFUNK_STATUS_IO = -7, PUNKTFUNK_STATUS_NULL_POINTER = -8, PUNKTFUNK_STATUS_TIMEOUT = -9, PUNKTFUNK_STATUS_CLOSED = -10, PUNKTFUNK_STATUS_PANIC = -99, }; #ifndef __cplusplus #if __STDC_VERSION__ >= 202311L typedef enum PunktfunkStatus PunktfunkStatus; #else typedef int32_t PunktfunkStatus; #endif // __STDC_VERSION__ >= 202311L #endif // __cplusplus // Kinds of input event. `#[repr(u8)]` so it crosses the C ABI as a byte tag. enum PunktfunkInputKind #if defined(__cplusplus) || __STDC_VERSION__ >= 202311L : uint8_t #endif // defined(__cplusplus) || __STDC_VERSION__ >= 202311L { PUNKTFUNK_INPUT_KIND_KEY_DOWN = 0, PUNKTFUNK_INPUT_KIND_KEY_UP = 1, // Relative motion: `x`/`y` carry `dx`/`dy`. PUNKTFUNK_INPUT_KIND_MOUSE_MOVE = 2, // Absolute motion: `x`/`y` carry pixel coordinates. PUNKTFUNK_INPUT_KIND_MOUSE_MOVE_ABS = 3, PUNKTFUNK_INPUT_KIND_MOUSE_BUTTON_DOWN = 4, PUNKTFUNK_INPUT_KIND_MOUSE_BUTTON_UP = 5, // `x` carries the (signed) scroll delta. PUNKTFUNK_INPUT_KIND_MOUSE_SCROLL = 6, // `code` = button bit ([`gamepad`] `BTN_*`), `x` ≠ 0 = pressed, `flags` = pad index. PUNKTFUNK_INPUT_KIND_GAMEPAD_BUTTON = 7, // `code` = axis id ([`gamepad`] `AXIS_*`), `x` = axis value, `flags` = pad index. // Sticks are i16 range (−32768..32767) in the XInput/Moonlight convention — **+y = // up** (unlike mouse coordinates); triggers 0..255. PUNKTFUNK_INPUT_KIND_GAMEPAD_AXIS = 8, // Touch begins. `code` = touch id (which finger; reusable after `TouchUp`), `x`/`y` = // pixel coordinates and `flags` = `(width << 16) | height` of the client's touch surface // — the same absolute mapping as [`MouseMoveAbs`](Self::MouseMoveAbs). PUNKTFUNK_INPUT_KIND_TOUCH_DOWN = 9, // Touch moves. Same field meaning as [`TouchDown`](Self::TouchDown). PUNKTFUNK_INPUT_KIND_TOUCH_MOVE = 10, // Touch ends. Only `code` (the touch id) is used. PUNKTFUNK_INPUT_KIND_TOUCH_UP = 11, }; #ifndef __cplusplus #if __STDC_VERSION__ >= 202311L typedef enum PunktfunkInputKind PunktfunkInputKind; #else typedef uint8_t PunktfunkInputKind; #endif // __STDC_VERSION__ >= 202311L #endif // __cplusplus #if defined(PUNKTFUNK_FEATURE_QUIC) // Opaque handle to a live `punktfunk/1` connection (QUIC control plane + UDP data plane, all // pumped on internal threads). // // Thread contract: each plane (video `next_au`, audio `next_audio`, rumble `next_rumble`) // may be pulled from its own thread, at most one thread per plane. The accessors only // take shared references internally (per-plane mutexed borrow slots), so cross-plane // concurrency is sound — never two threads on the *same* plane. typedef struct PunktfunkConnection PunktfunkConnection; #endif // Opaque session handle. Pointer-only from C. typedef struct PunktfunkSession PunktfunkSession; // Forward-compatible session configuration. The caller MUST set `struct_size` to // `sizeof(PunktfunkConfig)`; the core uses it to detect ABI skew. typedef struct { uint32_t struct_size; // 0 = host, 1 = client. uint32_t role; // 1 = P1 (GameStream-compatible), 2 = P2 (`punktfunk/1`). uint32_t phase; // 0 = GF(2⁸), 1 = GF(2¹⁶). uint32_t fec_scheme; uint32_t fec_percent; uint32_t max_data_per_block; uint32_t shard_payload; // Non-zero enables AES-128-GCM. uint32_t encrypt; uint8_t key[16]; uint8_t salt[4]; // Test hook for the loopback transport; 0 in production. uint32_t loopback_drop_period; // Largest encoded access unit the receiver will accept (bounds reassembler memory). uint64_t max_frame_bytes; } PunktfunkConfig; // A reassembled access unit. `data`/`len` borrow session-owned memory valid until the // next `punktfunk_client_poll_frame`/`punktfunk_session_free` on the same session. typedef struct { const uint8_t *data; uintptr_t len; uint32_t frame_index; uint64_t pts_ns; uint32_t flags; } PunktfunkFrame; // A single input event. `#[repr(C)]` — shared verbatim with the C ABI as // `PunktfunkInputEvent`. typedef struct { PunktfunkInputKind kind; uint8_t _pad[3]; // keycode / button id / axis id, depending on `kind`. uint32_t code; // x / dx / abs-x / axis-value / scroll-delta, depending on `kind`. int32_t x; // y / dy / abs-y, depending on `kind`. int32_t y; // modifier bitmask or gamepad index. uint32_t flags; } PunktfunkInputEvent; // Snapshot of session counters. typedef struct { uint64_t frames_submitted; uint64_t frames_completed; uint64_t frames_dropped; uint64_t packets_sent; uint64_t packets_received; uint64_t packets_dropped; // Packets dropped on the host send path because the kernel buffer was full (WouldBlock) — the // dominant loss mode at very high bitrate; distinct from `packets_dropped` (recv-side). uint64_t packets_send_dropped; uint64_t fec_recovered_shards; uint64_t bytes_sent; uint64_t bytes_received; } PunktfunkStats; #if defined(PUNKTFUNK_FEATURE_QUIC) // One Opus audio packet pulled off a `punktfunk/1` connection (48 kHz stereo, 5 ms frames). // `data` borrows connection memory until the next `punktfunk_connection_next_audio` call. typedef struct { const uint8_t *data; uintptr_t len; uint32_t seq; uint64_t pts_ns; } PunktfunkAudioPacket; #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // One DualSense HID-output feedback event a game wrote to the host's virtual pad // ([`punktfunk_connection_next_hidout`]). `kind` selects which fields are meaningful — replay it // on a real DualSense (lightbar color, player LEDs, or an adaptive-trigger effect via the // platform's `GCDualSenseAdaptiveTrigger`-style API). typedef struct { // One of `PUNKTFUNK_HIDOUT_*`. uint8_t kind; // Gamepad index. uint8_t pad; // LED: lightbar red. uint8_t r; // LED: lightbar green. uint8_t g; // LED: lightbar blue. uint8_t b; // PlayerLeds: lit player indicators (low 5 bits). uint8_t player_bits; // Trigger: 0 = L2, 1 = R2. uint8_t which; // Trigger: number of valid bytes in `effect` (≤ `PUNKTFUNK_HID_EFFECT_MAX`). uint8_t effect_len; // Trigger: the raw DualSense trigger parameter block (mode + params). uint8_t effect[11]; } PunktfunkHidOutput; #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // One rich client→host input for the host's virtual DualSense // ([`punktfunk_connection_send_rich_input`]): a touchpad contact or a motion sample. Set `kind` // and the matching fields; the others are ignored. typedef struct { // One of `PUNKTFUNK_RICH_*`. uint8_t kind; // Gamepad index. uint8_t pad; // Touchpad: contact id (0 or 1). uint8_t finger; // Touchpad: 1 = finger down, 0 = lifted. uint8_t active; // Touchpad: normalized x, 0..=65535 across the touchpad. uint16_t x; // Touchpad: normalized y, 0..=65535 across the touchpad. uint16_t y; // Motion: gyro (pitch, yaw, roll), raw signed-16. int16_t gyro[3]; // Motion: accelerometer (x, y, z), raw signed-16. int16_t accel[3]; } PunktfunkRichInput; #endif // A speed-test measurement, filled by [`punktfunk_connection_probe_result`]. `done` is 0 until // the host's end-of-burst report lands, then 1 (the numbers are final). `throughput_kbps` is the // measured goodput to drive a bitrate choice from; `loss_pct` is the delivery loss at that rate. typedef struct { // 1 once the host's end-of-burst report arrived (measurement final); else 0 (partial). uint8_t done; // Probe payload bytes / packets the client received. uint64_t recv_bytes; uint32_t recv_packets; // Probe payload bytes / packets the host reported sending. uint64_t host_bytes; uint32_t host_packets; // Client-measured receive window (first→last probe AU), milliseconds. uint32_t elapsed_ms; // Measured goodput = `recv_bytes * 8 / elapsed_ms` (kilobits/second). uint32_t throughput_kbps; // Delivery loss `(host_bytes - recv_bytes) / host_bytes` as a percentage (0 if unknown). float loss_pct; } PunktfunkProbeResult; #ifdef __cplusplus extern "C" { #endif // __cplusplus // Current ABI version. Mismatch with [`crate::ABI_VERSION`] means incompatible core. uint32_t punktfunk_abi_version(void); // Create a session over a real UDP transport (`local`/`peer` are `host:port` strings). // Returns NULL on error. // // # Safety // `cfg`, `local`, `peer` must be valid pointers; the strings must be NUL-terminated. PunktfunkSession *punktfunk_session_new(const PunktfunkConfig *cfg, const char *local, const char *peer); // Create a connected host+client session pair sharing an in-process loopback // transport. Test/dev only — exercises the full FEC + framing path without a network. // // # Safety // All four pointers must be valid; the two out-params receive owned handles. PunktfunkStatus punktfunk_test_loopback_pair(const PunktfunkConfig *host_cfg, const PunktfunkConfig *client_cfg, PunktfunkSession **out_host, PunktfunkSession **out_client); // Free a session handle. Safe to call with NULL. // // # Safety // `s` must be a handle from `punktfunk_session_new`/`punktfunk_test_loopback_pair`, freed once. void punktfunk_session_free(PunktfunkSession *s); // Host: FEC-protect, packetize, seal and send one encoded access unit. // // # Safety // `s` is a valid host handle; `data` points to `len` readable bytes (or `len == 0`). PunktfunkStatus punktfunk_host_submit_frame(PunktfunkSession *s, const uint8_t *data, uintptr_t len, uint64_t pts_ns, uint32_t flags); // Client: poll for the next reassembled access unit. Returns [`PunktfunkStatus::NoFrame`] // when nothing is ready yet. On `Ok`, `*out` borrows session memory until the next poll. // // # Safety // `s` is a valid client handle; `out` points to a writable `PunktfunkFrame`. PunktfunkStatus punktfunk_client_poll_frame(PunktfunkSession *s, PunktfunkFrame *out); // Client: serialize and send one input event to the host. // // # Safety // `s` is a valid client handle; `ev` points to a valid [`InputEvent`]. PunktfunkStatus punktfunk_send_input(PunktfunkSession *s, const PunktfunkInputEvent *ev); // Register the host-side input callback (pass a NULL fn pointer to clear). The callback // fires from within [`punktfunk_host_poll_input`], on the calling thread. // // # Safety // `s` is a valid host handle; `user` is passed back verbatim to `cb`. PunktfunkStatus punktfunk_set_input_callback(PunktfunkSession *s, void (*cb)(const PunktfunkInputEvent *event, void *user), void *user); // Host: drain all pending input events, invoking the registered callback for each. // Returns the count dispatched (≥ 0), or a negative [`PunktfunkStatus`] on error. // // # Safety // `s` is a valid host handle. int32_t punktfunk_host_poll_input(PunktfunkSession *s); // Copy session counters into `*out`. // // # Safety // `s` is a valid handle; `out` points to a writable `PunktfunkStats`. PunktfunkStatus punktfunk_get_stats(PunktfunkSession *s, PunktfunkStats *out); #if defined(PUNKTFUNK_FEATURE_QUIC) // Connect to a `punktfunk/1` host and start a session at `width`x`height`@`refresh_hz`. // Blocks up to `timeout_ms` for the handshake. Returns NULL on failure. Equivalent to // [`punktfunk_connect_ex`] with `compositor = PUNKTFUNK_COMPOSITOR_AUTO`. // // Trust: `pin_sha256` (NULL or 32 bytes) is the expected SHA-256 fingerprint of the host's // certificate — a mismatching host is rejected. NULL = trust on first use; persist the // fingerprint written to `observed_sha256_out` (NULL or 32 bytes, filled on success) and // pass it as the pin on every later connect. // // Identity: `client_cert_pem`/`client_key_pem` (both NULL, or both NUL-terminated PEM // strings — see [`punktfunk_generate_identity`]) are presented via TLS client auth so a // host can recognize this client once paired ([`punktfunk_pair`]). NULL = anonymous; // hosts running `--require-pairing` reject anonymous sessions. // // # Safety // `host` is a NUL-terminated UTF-8 string (IP or hostname resolvable by the platform); // `pin_sha256`/`observed_sha256_out` are each NULL or valid for 32 bytes; // `client_cert_pem`/`client_key_pem` are each NULL or NUL-terminated UTF-8. PunktfunkConnection *punktfunk_connect(const char *host, uint16_t port, uint32_t width, uint32_t height, uint32_t refresh_hz, const uint8_t *pin_sha256, uint8_t *observed_sha256_out, const char *client_cert_pem, const char *client_key_pem, uint32_t timeout_ms); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Like [`punktfunk_connect`], but requests a specific `compositor` backend on the host (one of // the `PUNKTFUNK_COMPOSITOR_*` values). `PUNKTFUNK_COMPOSITOR_AUTO` (or any unrecognized value) // lets the host decide; a concrete value is honored only if available, else the host falls back // to auto-detect. The resolved choice is logged host-side and returned over the protocol. // Equivalent to [`punktfunk_connect_ex2`] with `gamepad = PUNKTFUNK_GAMEPAD_AUTO`. // // # Safety // Same as [`punktfunk_connect`]. PunktfunkConnection *punktfunk_connect_ex(const char *host, uint16_t port, uint32_t width, uint32_t height, uint32_t refresh_hz, uint32_t compositor, const uint8_t *pin_sha256, uint8_t *observed_sha256_out, const char *client_cert_pem, const char *client_key_pem, uint32_t timeout_ms); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Like [`punktfunk_connect_ex`], but additionally requests which virtual `gamepad` backend the // host creates for this session's pads (one of the `PUNKTFUNK_GAMEPAD_*` values). // `PUNKTFUNK_GAMEPAD_AUTO` (or any unrecognized value) lets the host decide (its // `PUNKTFUNK_GAMEPAD` env var, else X-Box 360); a concrete value is honored only if that // backend is available on the host. The resolved choice is readable via // [`punktfunk_connection_gamepad`] — only a DualSense session emits HID-output feedback. // // # Safety // Same as [`punktfunk_connect`]. PunktfunkConnection *punktfunk_connect_ex2(const char *host, uint16_t port, uint32_t width, uint32_t height, uint32_t refresh_hz, uint32_t compositor, uint32_t gamepad, const uint8_t *pin_sha256, uint8_t *observed_sha256_out, const char *client_cert_pem, const char *client_key_pem, uint32_t timeout_ms); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Like [`punktfunk_connect_ex2`], but additionally requests the video encoder `bitrate_kbps` // (kilobits per second). `0` lets the host pick its default; any other value is clamped to the // host's supported range. After a speed test ([`punktfunk_connection_speed_test`]) a client can // reconnect (or pick at connect time) with the measured rate. The value the host actually // configured is readable via [`punktfunk_connection_bitrate`]. // // # Safety // Same as [`punktfunk_connect`]. PunktfunkConnection *punktfunk_connect_ex3(const char *host, uint16_t port, uint32_t width, uint32_t height, uint32_t refresh_hz, uint32_t compositor, uint32_t gamepad, uint32_t bitrate_kbps, const uint8_t *pin_sha256, uint8_t *observed_sha256_out, const char *client_cert_pem, const char *client_key_pem, uint32_t timeout_ms); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Generate a persistent client identity: a self-signed certificate + private key, both // PEM, NUL-terminated, written into the caller's buffers. Generate ONCE, store both // strings (Keychain etc.), pass them to [`punktfunk_pair`] and every // [`punktfunk_connect`] — the certificate's fingerprint is how hosts recognize this // client. 4096-byte buffers are ample. // // # Safety // `cert_pem_out` is writable for `cert_cap` bytes; `key_pem_out` for `key_cap`. PunktfunkStatus punktfunk_generate_identity(char *cert_pem_out, uintptr_t cert_cap, char *key_pem_out, uintptr_t key_cap); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Run the PIN pairing ceremony against a host (see the protocol docs in punktfunk-core): // the host displays a short PIN; the user types it into the client app, which passes it // here. On success the host has stored this client's identity, the now-verified host // fingerprint is written to `host_sha256_out` (32 bytes) — persist it and pass it as // `pin_sha256` to [`punktfunk_connect`] from then on. Returns // [`PunktfunkStatus::Crypto`] for a wrong PIN. // // # Safety // `host`/`client_cert_pem`/`client_key_pem`/`pin`/`name` are NUL-terminated UTF-8; // `host_sha256_out` is writable for 32 bytes. PunktfunkStatus punktfunk_pair(const char *host, uint16_t port, const char *client_cert_pem, const char *client_key_pem, const char *pin, const char *name, uint8_t *host_sha256_out, uint32_t timeout_ms); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Pull the next reassembled access unit, waiting up to `timeout_ms`. Returns // [`PunktfunkStatus::NoFrame`] on timeout and [`PunktfunkStatus::Closed`] once the session ended. // On `Ok`, `*out` borrows connection memory **until the next `next_au` call** on this // handle (the audio/rumble planes do not invalidate it). // // # Safety // `c` is a valid connection handle; `out` is writable. At most one thread pulls video — // it may run concurrently with one audio-pulling and one rumble-pulling thread. PunktfunkStatus punktfunk_connection_next_au(PunktfunkConnection *c, PunktfunkFrame *out, uint32_t timeout_ms); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Pull the next Opus audio packet, waiting up to `timeout_ms`. Returns // [`PunktfunkStatus::NoFrame`] on timeout and [`PunktfunkStatus::Closed`] once the session ended. // On `Ok`, `out->data` borrows connection memory **until the next audio call** on this // handle (independent of the video slot). Drain from a dedicated audio thread — packets // arrive every 5 ms and the internal queue holds 320 ms. // // # Safety // `c` is a valid connection handle; `out` is writable. At most one thread pulls audio — // it may run concurrently with the video/rumble pullers. PunktfunkStatus punktfunk_connection_next_audio(PunktfunkConnection *c, PunktfunkAudioPacket *out, uint32_t timeout_ms); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Pull the next rumble (force-feedback) update, waiting up to `timeout_ms`. Amplitudes // are 0..0xFFFF (`low` = low-frequency motor, `high` = high-frequency), `(0, 0)` = stop. // Same timeout/closed semantics as [`punktfunk_connection_next_audio`]. // // # 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(PunktfunkConnection *c, uint16_t *pad, uint16_t *low, uint16_t *high, uint32_t timeout_ms); #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 // timeout, [`PunktfunkStatus::Closed`] once the session ended. Only the DualSense host backend // emits these. Same threading rules as [`punktfunk_connection_next_rumble`] (one puller, may run // alongside the other planes). // // # Safety // `c` is a valid connection handle; `out` is writable for one `PunktfunkHidOutput`. PunktfunkStatus punktfunk_connection_next_hidout(PunktfunkConnection *c, PunktfunkHidOutput *out, uint32_t timeout_ms); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Send one input event to the host as a QUIC datagram (non-blocking enqueue). // // # Safety // `c` is a valid connection handle; `ev` points to a valid [`InputEvent`]. PunktfunkStatus punktfunk_connection_send_input(PunktfunkConnection *c, const PunktfunkInputEvent *ev); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Send one Opus mic frame to the host as a QUIC datagram (48 kHz; the host decodes it into a // virtual microphone source its apps can record). Non-blocking enqueue; the host uses `seq`/ // `pts_ns` (the caller's own counters) only for diagnostics. `opus_data`/`len` may be empty // (a DTX silence frame). The data is copied; the caller may reuse the buffer after this returns. // // # Safety // `c` is a valid connection handle; `opus_data` is valid for `len` bytes (or `len == 0`). PunktfunkStatus punktfunk_connection_send_mic(PunktfunkConnection *c, const uint8_t *opus_data, uintptr_t len, uint32_t seq, uint64_t pts_ns); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Send one rich input event (DualSense touchpad contact or motion sample) to the host as a QUIC // datagram (non-blocking enqueue). The host applies it to its virtual DualSense pad — a no-op // unless the host runs the DualSense gamepad backend. [`PunktfunkStatus::InvalidArg`] on an // unknown `kind`. // // # Safety // `c` is a valid connection handle; `rich` points to a valid [`PunktfunkRichInput`]. PunktfunkStatus punktfunk_connection_send_rich_input(PunktfunkConnection *c, const PunktfunkRichInput *rich); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // The currently active session mode — the Welcome's, until an accepted // [`punktfunk_connection_request_mode`] switches it. Safe any time after connect. // // # Safety // `c` is a valid connection handle; out pointers are writable (NULLs are skipped). PunktfunkStatus punktfunk_connection_mode(const PunktfunkConnection *c, uint32_t *width, uint32_t *height, uint32_t *refresh_hz); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // The virtual gamepad backend the host actually resolved for this session (one of the // `PUNKTFUNK_GAMEPAD_*` values; the `Welcome`'s echo of the [`punktfunk_connect_ex2`] // preference). `PUNKTFUNK_GAMEPAD_AUTO` = an older host that didn't say — assume X-Box 360, // no HID-output feedback. Safe any time after connect. // // # Safety // `c` is a valid connection handle; `gamepad` is writable (NULL is skipped). PunktfunkStatus punktfunk_connection_gamepad(const PunktfunkConnection *c, uint32_t *gamepad); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // The video encoder bitrate (kilobits per second) the host actually configured for this session // — the [`punktfunk_connect_ex3`] request clamped to the host's range, or its default when `0` // was requested. `0` = an older host that didn't report it. Safe any time after connect. // // # Safety // `c` is a valid connection handle; `bitrate_kbps` is writable (NULL is skipped). PunktfunkStatus punktfunk_connection_bitrate(const PunktfunkConnection *c, uint32_t *bitrate_kbps); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // The host↔client wall-clock offset (nanoseconds, **host minus client**) measured by the // connect-time skew handshake. Add it to a local receive/present timestamp (same realtime clock, // `CLOCK_REALTIME` / `gettimeofday`-epoch nanoseconds) to express that instant in the host's // capture clock — the clock the per-access-unit `pts_ns` is stamped in — so glass-to-glass latency // (e.g. present-time minus `pts_ns`) is valid across machines. `0` = no correction: either an older // host that didn't answer the handshake, or genuinely synchronized clocks. Safe any time after // connect. // // # Safety // `c` is a valid connection handle; `offset_ns` is writable (NULL is skipped). PunktfunkStatus punktfunk_connection_clock_offset_ns(const PunktfunkConnection *c, int64_t *offset_ns); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Ask the host to switch the live session to `width`x`height`@`refresh_hz` without // reconnecting (window resized, refresh changed). Non-blocking enqueue: on acceptance the // stream continues at the new mode — the first new-mode access unit is an IDR with // in-band parameter sets (rebuild the decoder from it) — and // [`punktfunk_connection_mode`] reflects the switch. A rejected request leaves the // session unchanged. // // # Safety // `c` is a valid connection handle. PunktfunkStatus punktfunk_connection_request_mode(const PunktfunkConnection *c, uint32_t width, uint32_t height, uint32_t refresh_hz); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Start a bandwidth speed test: ask the host to burst filler over the data plane at // `target_kbps` of goodput for `duration_ms` (each clamped host-side to ≤ 3 Gbps / ≤ 5 s), // *briefly pausing video*. Non-blocking — poll [`punktfunk_connection_probe_result`] until its // `done` field is 1. Starting a probe resets any prior measurement. // // # Safety // `c` is a valid connection handle. PunktfunkStatus punktfunk_connection_speed_test(const PunktfunkConnection *c, uint32_t target_kbps, uint32_t duration_ms); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Read the current speed-test measurement into `*out` (partial until `out->done == 1`). Safe to // poll repeatedly after [`punktfunk_connection_speed_test`]; before any probe it reports zeros. // // # Safety // `c` is a valid connection handle; `out` is writable for one `PunktfunkProbeResult` (NULL is an // error). PunktfunkStatus punktfunk_connection_probe_result(const PunktfunkConnection *c, PunktfunkProbeResult *out); #endif #if defined(PUNKTFUNK_FEATURE_QUIC) // Close the connection and free the handle (joins the internal threads). NULL is a no-op. // // # Safety // `c` was returned by [`punktfunk_connect`] and is not used after this call. void punktfunk_connection_close(PunktfunkConnection *c); #endif #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif /* PUNKTFUNK_CORE_H */