Pose

Real-time pose streaming (WebSocket — on-demand)

Dedicated WebSocket endpoint for 60fps skeleton streaming.

The WebSocket server is NOT started at boot. Call POST /v1/pose/stream/start first — the response includes the actual port and endpoint URL. The server prefers port 10005 but uses an OS-assigned port if 10005 is occupied.

Endpoint: ws://127.0.0.1:<port> (separate port, not on 9998) Auth: Bearer token via the Sec-WebSocket-Protocol upgrade header. Open with new WebSocket(url, ['bearer.toolpiper.v1', 'bearer.<token>', 'corr.<uuid>']) — see docs/archive/local-http-auth-bearer-only-paths.md § Phase 2. Max concurrent: 4 streams

Lifecycle

  1. POST /v1/pose/stream/start — starts the WebSocket server, returns { port, endpoint }
  2. Connect to the returned endpoint URL
  3. GET /v1/pose/stream/status — check running state and connection count
  4. POST /v1/pose/stream/stop — stops the server (or let it run)

Client → Server

MessageWS TypeDescription
{"type":"config", ...}textConfigure session (optional — defaults apply)
Raw JPEG/PNG bytesbinaryOne frame per message
{"type":"record","action":"start"}textStart recording to ring buffer
{"type":"record","action":"stop"}textStop recording
{"type":"eos"}textEnd session

Config message (all fields optional)

{
  "type": "config",
  "backend": "apple-vision",
  "topology": "openpose-18",
  "format": "compact-binary",
  "include_hands": false,
  "include_face": false,
  "detect_3d": false,
  "confidence_threshold": 0.3,
  "canvas_width": 1024,
  "canvas_height": 1024,
  "renderer": "openpose",
  "stats_interval_ms": 1000
}

Server → Client

MessageWS TypeDescription
{"type":"config_ack", "joint_order":[...]}textResolved config + joint order for binary decoding
Pose databinary or textFormat depends on config (see Output Formats)
{"type":"stats", ...}textPeriodic fps, drop rate, avg detection time
{"type":"record_ack", ...}textRecording start/stop confirmation
{"type":"error","message":"..."}textError

Output Formats

compact-binary (default) — Binary WS message. Pre-allocated buffer, zero heap alloc per frame. 236 bytes for 1 person / OpenPose-18 / 2D:

  • Header (16B): magic 0x504F5345, version, flags, num_people, num_joints, detection_ms, frame_seq
  • Per-person: optional bbox (4×f32), confidence (f32), per-joint x/y/confidence (3×f32 each, +z if 3D)

compact-json — Text WS message. Short keys, flat arrays, pixel-space coords. {"f":42,"ms":8.3,"n":1,"p":[[512.0,307.2,0.95,...]]}

verbose-json — Text WS message. Named joints, full metadata. {"type":"pose","frame_seq":42,"detection_ms":8.3,"people":[{"keypoints":{"nose":{"x":0.5,"y":0.3,"c":0.95},...}}]}

image — Binary WS message (PNG). Rendered skeleton via selected renderer. Cannot sustain 60fps.

get/v1/pose/stream

Request

  • Base URL: http://localhost:9998
  • URL: http://localhost:9998/v1/pose/stream
  • Auth: HTTP bearer

Changes

No recorded changes to this operation across all 1 revision of this API.