Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions docs/PERFORMANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,12 @@ should add as close to zero as possible.
cover (`CameraPreviewView.previewEnabled`). The outgoing stream is
unaffected. On top of the existing OLED-black + brightness drop, this
is the biggest saver for the "phone mounted behind the monitor" case.
- **Background PiP feeds a 1-point layer while armed, and nothing when
it isn't.** `BackgroundPiP.enqueue` returns on a lock-guarded flag
whenever background streaming is off or nothing is streaming. While a
stream *is* armed for PiP the layer is fed continuously, even before a
window opens — PiP adopts a layer that is already showing something,
and a layer fed nothing has nothing to hand over — so the cost is one
`enqueue` into a one-point display layer per frame. The buffers are
the ones the encoder already has (no second capture, no second
composite), and frames the layer isn't ready for are dropped rather
than queued.
- **Background PiP costs one boolean read per frame while inline.** The
frame tee into the PiP window (`BackgroundPiP.enqueue`) returns on a
lock-guarded flag until a window is actually open, so the on-screen
path is unchanged; once open, the window is fed the buffers the
encoder already has (no second capture, no second composite) and drops
frames the display layer isn't ready for rather than queueing them.
- Idle standby listener costs nothing measurable: no timers, no camera —
just an accepting socket and 1 Hz timesync replies while OBS is
connected.
Expand Down
19 changes: 19 additions & 0 deletions docs/PROTOCOL.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ Camera remote control. Payload: UTF-8 JSON, one command per packet:
{ "cmd": "exposure", "mode": "auto" }
{ "cmd": "start_stream" }
{ "cmd": "stop_stream" }
{ "cmd": "pause_stream" }
{ "cmd": "resume_stream" }
{ "cmd": "set_format", "resolution": "1080p", "fps": 60, "codec": "hevc" }
{ "cmd": "mic", "id": "builtin:2" }
{ "cmd": "tally", "program": true, "preview": false, "sync": "locked" }
Expand Down Expand Up @@ -189,6 +191,15 @@ Camera connections only; screen mirror ignores it.
Unknown commands are ignored, so new ones can be added compatibly. The
plugin's embedded web panel (http://localhost:9980) generates these.

`pause_stream` / `resume_stream` **hold** a running stream instead of
ending it: the app keeps the connection, the camera and the encoder, and
simply stops sending VIDEO. Audio is unaffected — a phone acting as the
wireless mic keeps carrying the show. Resuming asks the encoder for a
keyframe, so the plugin has something self-contained to restart decoding
on. Unlike remote start these need no **Remote start from OBS**
permission: they can only hold a stream the user already started, never
turn a camera on.

`start_stream` / `stop_stream` are the **remote start** commands: they
start/stop the camera itself (not just the connection) and are honoured
only while the app's **Remote start from OBS** option is on. The plugin
Expand Down Expand Up @@ -229,6 +240,14 @@ H.264 through the ordinary `set_format` validation. Both fields are
absent on SDR streams, whose snapshots are unchanged from before
colour modes existed.

Pause rides the snapshot too: `"paused": true` while video is held, with
`"pauseReason"` saying who held it — `"user"` for an operator pause (the
app's Pause button, the web panel, or the source properties) or
`"camera"` when iOS took the camera away, which happens when a PiP
window carrying a background stream is parked at the screen edge. The
reason is what lets a surface choose between offering a Resume button
and explaining that the phone is waiting on iOS.

Green screen state rides the snapshot the same way:
`"supportsGreenScreen": true` advertises the feature (remote UIs gate
their row on it), `"greenScreen": true` appears while it is armed,
Expand Down
10 changes: 10 additions & 0 deletions docs/UI_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,18 @@ colours so it also looks native on the phone.
| Standby | `connectAmber`| `#FF9F0A` | "OBS connected — ready" |
| Connecting | `connectAmber`| `#FF9F0A` | "Waiting for OBS…" |
| Live | `liveGreen` | `#30D158` | "Live" |
| Paused | `connectAmber`| `#FF9F0A` | "Paused" |
| Error | `errorRed` | `#FF453A` | *(the message)* |

Paused is a **held** stream, not a broken one: connected, camera
running, no video going out. It takes the same amber as Standby and
Connecting — connected but not live — and is always the single word
"Paused". An operator pause (the Live screen's pause chip, the web
panel, the source properties) says exactly that; a pause iOS forced by
taking the camera keeps its explanatory message instead, because there
the sentence is the actionable part. Either way the plugin learns of it
through STATE and says so rather than sitting on a frozen picture.

Standby is the remote-start state: the app is idle but OBS is connected
and can start the camera. It shares the amber of Connecting — both mean
"linked, not yet live". On the web panel the standby state replaces the
Expand Down
Loading