@mega-yfue/eufy-sdk / LiveTrace
Type Alias: LiveTrace
type LiveTrace =
| {
action: "start" | "keepalive";
level2: boolean;
phase: "media-command";
topology: "attached" | "own";
}
| {
action: "start";
phase: | "media-command-ack"
| "media-command-retry"
| "media-command-unacknowledged";
}
| {
accepted: boolean;
phase: "first-video-command";
signCode: number;
}
| {
keyframe: boolean;
phase: "first-video-unit";
}
| {
phase: "first-keyframe";
}
| {
media: "audio" | "video";
phase: "first-foreign-media-command";
}
| {
phase: "video-decode-empty";
signCode: number;
}
| {
dataType: number;
phase: "datagram-gap";
}
| {
dataType: number;
phase: "sequence-restart";
}
| {
cloud: boolean;
cloudMissing?: "dsk-key" | "cloud-addresses";
local: boolean;
phase: "lookup-channels";
}
| {
phase: "session-connect-wait";
waitMs: number;
}
| {
phase: "session-connected";
waitedMs: number;
}
| {
phase: "session-unreachable";
waitedMs: number;
}
| {
phase: "level2-wait";
waitMs: number;
}
| {
cipherId: number;
phase: "level2-ready";
}
| {
cipherId: number;
phase: "level2-set-payload-only";
}
| {
cipherId?: number;
phase: "level2-unavailable";
reason: | "no-cipher-key"
| "derivation-failed"
| "not-negotiating"
| "session-closed"
| "grace-elapsed";
waitedMs?: number;
}
| {
answeredCipherId: number;
cipherId: number;
phase: "cipher-fallback";
}
| {
cipherId: number;
phase: "level2-negotiating";
}
| {
channel: number;
phase: "station-resolved";
stationAdmin: "self" | "other" | "unstated";
stationModel?: string;
topology: "attached" | "own";
}
| {
issue: "missing" | "shared";
phase: "station-channel-unresolved";
}
| {
deadlineMs: number;
phase: "warming";
retryMs: number;
}
| {
phase: "media-command-unsent";
reason: "level2-key" | "address";
}
| {
phase: "path-stale";
silentMs: number;
}
| {
outcome: "reasserted" | "declined";
phase: "channel-silent";
silentMs: number;
}
| {
attempts: number;
errorName?: string;
phase: "start-failed";
reason: LiveStreamStartFailureReason;
stage: LiveStreamStartStage;
};One bounded startup observation.
Union Members
Type Literal
{
action: "start" | "keepalive";
level2: boolean;
phase: "media-command";
topology: "attached" | "own";
}A media start or keepalive was sent, with the topology and encryption level it was sent under.
Type Literal
{
action: "start";
phase: | "media-command-ack"
| "media-command-retry"
| "media-command-unacknowledged";
}The device acknowledged a retained start, or that start was repeated / abandoned unacknowledged.
Type Literal
{
accepted: boolean;
phase: "first-video-command";
signCode: number;
}The first inbound video command, and whether this stream's channel filter accepted it.
Type Literal
{
keyframe: boolean;
phase: "first-video-unit";
}The first reassembled video access unit, and whether it was decodable on its own.
Type Literal
{
phase: "first-keyframe";
}The first keyframe reached the consumer.
Type Literal
{
media: "audio" | "video";
phase: "first-foreign-media-command";
}Media tagged for another camera on the same station arrived first.
Type Literal
{
phase: "video-decode-empty";
signCode: number;
}A video payload decoded to nothing, so no access unit could be built from it.
Type Literal
{
dataType: number;
phase: "datagram-gap";
}A datagram was missing on a data channel, discarding the logical frame being reassembled.
Type Literal
{
dataType: number;
phase: "sequence-restart";
}A data channel's numbering restarted mid-connection, so sequencing resynchronized onto it.
Type Literal
{
cloud: boolean;
cloudMissing?: "dsk-key" | "cloud-addresses";
local: boolean;
phase: "lookup-channels";
}Which lookup channels a connection can ask for the station on, before it asks.
A station is found by a local lookup, by a cloud lookup, or by both, and each needs something the other does not: the local one needs the station on this link, the cloud one needs both a key for the station and an address to ask. A connect that had one channel failed for that channel's reason alone, and a connect that had neither could not have succeeded — outcomes a station that is switched off is otherwise indistinguishable from, because nothing else in a failed connect states what was even attempted.
cloudMissing names the input the cloud channel lacked, present exactly when cloud is false: dsk-key where no key was held for the station, cloud-addresses where its record named no address to ask. The key is named where both are absent.
Type Literal
{
phase: "session-connect-wait";
waitMs: number;
}Work on a station is holding for its session to connect, with the milliseconds it will wait.
The earliest phase there is: nothing else on a station can be attempted until its session is up, and a caller whose own deadline expires inside this wait has this record and no other. Emitted only where a wait actually happens, so its absence states that the session was already connected.
Type Literal
{
phase: "session-connected";
waitedMs: number;
}The session connected, after this long.
Type Literal
{
phase: "session-unreachable";
waitedMs: number;
}The session did not connect within its wait, so nothing on this station can be attempted.
The one outcome that is otherwise indistinguishable from a station that answered and then refused: both leave a caller with no media and no phase naming a station.
Type Literal
{
phase: "level2-wait";
waitMs: number;
}A live start is holding for the station's level-2 key, with the milliseconds it will wait.
A start that looks slow is either waiting here, waiting for its session to connect, waiting for the station to serve the channel it was asked for, or being re-issued — and only these phases separate them.
Type Literal
{
cipherId: number;
phase: "level2-ready";
}The station's AES-256-GCM level-2 key was negotiated, under the cipher it selected.
Type Literal
{
cipherId: number;
phase: "level2-set-payload-only";
}The station's cipher negotiated only the AES-128-ECB level-2 key of an RSA cipher, under the cipher it selected. That key seals a level-2 set-payload and nothing else, so this is not level2-ready.
Type Literal
{
cipherId?: number;
phase: "level2-unavailable";
reason: | "no-cipher-key"
| "derivation-failed"
| "not-negotiating"
| "session-closed"
| "grace-elapsed";
waitedMs?: number;
}The station's key is not coming, why, and the cipher where a station named one.
Every ending of a level-2 wait carries one of these reasons, so a start refused for want of a key is accounted for however it ended. grace-elapsed is a wait that ran out and states how long was waited; the rest are answered without waiting, because the negotiation is one-shot per connection and a concluded one is final. no-cipher-key and derivation-failed are about this account's cipher material, not-negotiating and session-closed about the station or its connection — and only a reason reached under a negotiation has a cipher to name.
A grace-elapsed start proceeds at level 1 where it has such a form, and not at all where it does not.
Type Literal
{
answeredCipherId: number;
cipherId: number;
phase: "cipher-fallback";
}A station's cipher was answered with material for a DIFFERENT cipher, which was used in its place.
The one lookup outcome no other phase accounts for: material for the cipher the station named is followed by level2-ready, level2-set-payload-only or level2-unavailable with derivation-failed, an answer holding none by no-cipher-key, and a lookup that threw is reported as an error. Substituted material derives to nothing and otherwise reads as a station fault. cipherId is the cipher the station asked for, answeredCipherId the one whose material was used.
Type Literal
{
cipherId: number;
phase: "level2-negotiating";
}The station answered its gateway-info prompt, so a key derivation has begun under the cipher it named.
What separates a station that never answered the prompt from one that answered and produced no usable key: without it, level2-unavailable with not-negotiating covers both, and they are a station or network problem and an account cipher-material problem respectively.
Type Literal
{
channel: number;
phase: "station-resolved";
stationAdmin: "self" | "other" | "unstated";
stationModel?: string;
topology: "attached" | "own";
}A station was resolved for a call, stating what the caller's device is on it and whose station it is.
Emitted before the session is waited on, so a station that is never reached still has this record: an attached camera's media start has no unencrypted form, so whether a device was taken as attached decides what its failure means. stationAdmin states whether the signed-in account is the station's administrator, which is what a key the account cannot resolve turns on; unstated is a device record that names no administrator, which is not the same as naming another. stationModel is the model of the station the call resolved — the base's for an attached camera, the device's own where it is its own station — absent where that record states none; without it a base this SDK reaches differently is indistinguishable from one that is switched off.
Type Literal
{
issue: "missing" | "shared";
phase: "station-channel-unresolved";
}The call's device has no usable channel on the station it resolved: its record states none (missing), or another device attached to the same station states the same one (shared). The call is refused with DeviceChannelUnresolvedError and nothing is sent.
Type Literal
{
deadlineMs: number;
phase: "warming";
retryMs: number;
}A shared source began warming, with the interval it re-issues on and the deadline it fails at.
Type Literal
{
phase: "media-command-unsent";
reason: "level2-key" | "address";
}A media command was never put on the wire, and what it was missing.
The attached media start has no level-1 form, so without the station's level-2 key there is nothing to send. A command that was never sent is otherwise indistinguishable from one the station ignored, which is the difference between a key that never arrived and a station that is not answering.
Type Literal
{
phase: "path-stale";
silentMs: number;
}This connection's path has stopped answering the heartbeat, with how long it has been silent.
The station answers every PING with a PONG, so silence past several heartbeats is the path being gone. Stated only where a pong arrived: a station that has never answered says nothing by not answering now.
Type Literal
{
outcome: "reasserted" | "declined";
phase: "channel-silent";
silentMs: number;
}A stream received nothing on its own channel for the stall window, and what was done about it.
A station that switches to a sibling leaves the stream it was serving with no frames, no error and no stop, so this silence is the only statement that it happened. reasserted re-issued the media start, which is the repair; declined left the channel alone because nothing is attached to this pull and taking the station back would take it from a camera someone is watching.
Media still arriving means this never fires, so a picture that stopped advancing while this is silent stopped for a reason upstream of the station's attention.
Type Literal
{
attempts: number;
errorName?: string;
phase: "start-failed";
reason: LiveStreamStartFailureReason;
stage: LiveStreamStartStage;
}A live start failed, with the facts of the LiveStreamStartError it was refused with.
errorName is the upstream error's class name, present for source-error only; its message is never carried, because an upstream message can name a station.