@furious.luke/argus-js 0.5.5 → 0.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -79,6 +79,11 @@ type SignalMessage = {
79
79
  track: TrackType;
80
80
  track_id?: string;
81
81
  reason?: string;
82
+ } | {
83
+ type: "speech_slow";
84
+ realtime_factor: number;
85
+ } | {
86
+ type: "speech_recovered";
82
87
  } | {
83
88
  type: "recovery_event";
84
89
  event: "recovery_started" | "recovery_retry" | "recovery_failed";
@@ -131,6 +136,32 @@ interface PublisherCallbacks {
131
136
  onUserTextResult?: (event: UserTextResultEvent) => void;
132
137
  /** Called once the explicitly requested outbound speech track arrives. */
133
138
  onSpeechTrack?: (track: MediaStreamTrack, streams: readonly MediaStream[]) => void;
139
+ /**
140
+ * Called when server-side text-to-speech generation crosses the realtime
141
+ * boundary: `degraded: true` when the TTS provider drops below realtime
142
+ * (`realtimeFactor` < 1.0), synthesizing audio slower than it plays and starving
143
+ * playout regardless of the network, and `degraded: false` when a later utterance
144
+ * climbs comfortably back above realtime. The degraded transition is raised live
145
+ * during synthesis — a long, slow utterance is reported while it is happening, not
146
+ * once it finishes. Edge-triggered — fires only on the transition, not per
147
+ * utterance, and a factor hovering at the boundary does not flap it. This is a
148
+ * distinct axis from {@link onConnectionQualityChange} (which is network health);
149
+ * react by, e.g., warning the user or offering a text fallback.
150
+ */
151
+ onSpeechQualityChange?: (event: SpeechQualityEvent) => void;
152
+ /**
153
+ * Called for every periodic connection-stats sample while connected — the raw
154
+ * feed behind {@link onConnectionQualityChange}. Fires at
155
+ * {@link PublisherOptions.connectionStatsIntervalMs}.
156
+ */
157
+ onConnectionStats?: (sample: ConnectionStatsSample) => void;
158
+ /**
159
+ * Called when the derived connection-quality level changes (including the
160
+ * first assessment after connecting). Downgrades are debounced; upgrades fire
161
+ * immediately. Use this to react to a degrading network — e.g. warn the user
162
+ * or drop a secondary track.
163
+ */
164
+ onConnectionQualityChange?: (quality: ConnectionQuality) => void;
134
165
  }
135
166
  interface AssistantTextEvent {
136
167
  utteranceId: string;
@@ -144,6 +175,97 @@ interface UserTextResultEvent {
144
175
  accepted: boolean;
145
176
  reason?: string;
146
177
  }
178
+ /**
179
+ * A change in server-side text-to-speech generation health, delivered to
180
+ * {@link PublisherCallbacks.onSpeechQualityChange}. `degraded` is `true` on the
181
+ * transition into below-realtime synthesis (`realtimeFactor` < 1.0) and `false`
182
+ * once synthesis climbs comfortably back above realtime. `realtimeFactor` (audio
183
+ * produced ÷ wall-clock to produce it) accompanies a degraded transition.
184
+ */
185
+ interface SpeechQualityEvent {
186
+ degraded: boolean;
187
+ realtimeFactor?: number;
188
+ }
189
+ /**
190
+ * A coarse assessment of the uplink to the media server, derived from periodic
191
+ * WebRTC stats. Ordered worst-last by severity: `"good"` is a healthy
192
+ * connection, `"critical"` is barely usable.
193
+ */
194
+ type ConnectionQualityLevel = "good" | "fair" | "poor" | "critical";
195
+ /**
196
+ * One periodic sample of the outbound connection's health, taken from
197
+ * `RTCPeerConnection.getStats()`. Packet loss and send bitrate are windowed over
198
+ * the interval since the previous sample (the first sample covers the session so
199
+ * far); the rest are point-in-time readings. A field is `null` when the browser
200
+ * did not report the underlying stat for this sample.
201
+ */
202
+ interface ConnectionStatsSample {
203
+ /** Monotonic clock timestamp (ms) when the sample was taken. */
204
+ timestamp: number;
205
+ /**
206
+ * Fraction of outbound RTP packets lost, in `0..1` — the primary quality
207
+ * signal. A traffic-weighted mean of each stream's loss fraction: a stream uses
208
+ * its remote `fractionLost` (its loss ratio over the last RTCP report interval)
209
+ * when present, otherwise its windowed
210
+ * `Δpacketslost / Δ(packetsSent - retransmittedPacketsSent)`. Both kinds of
211
+ * stream are combined, so a lossy stream is never dropped for lacking
212
+ * `fractionLost`.
213
+ */
214
+ lossRatio: number;
215
+ /** Round-trip time in milliseconds, or `null` if unknown. */
216
+ rttMs: number | null;
217
+ /** Inter-arrival jitter in milliseconds, or `null` if unknown. */
218
+ jitterMs: number | null;
219
+ /** ICE-estimated available outgoing bitrate in bits/sec, or `null` if unknown. */
220
+ availableOutgoingBitrate: number | null;
221
+ /** Actual send bitrate over the interval in bits/sec, or `null` if unknown. */
222
+ sendBitrate: number | null;
223
+ /**
224
+ * Why the encoder is limiting quality: `"none"`, `"cpu"`, `"bandwidth"`, or
225
+ * `"other"`. `null` when no video is being sent. `"bandwidth"` is treated as a
226
+ * degradation signal by the default classifier.
227
+ */
228
+ qualityLimitationReason: string | null;
229
+ /** Cumulative NACKs received on outbound media, or `null` if unknown. */
230
+ nackCount: number | null;
231
+ /** Cumulative PLIs received on outbound media, or `null` if unknown. */
232
+ pliCount: number | null;
233
+ }
234
+ /**
235
+ * A committed connection-quality assessment, delivered to
236
+ * {@link PublisherCallbacks.onConnectionQualityChange} whenever the level
237
+ * changes. `sample` is the reading that triggered the transition.
238
+ */
239
+ interface ConnectionQuality {
240
+ level: ConnectionQualityLevel;
241
+ sample: ConnectionStatsSample;
242
+ }
243
+ /**
244
+ * Thresholds mapping a {@link ConnectionStatsSample} to a
245
+ * {@link ConnectionQualityLevel}. Packet loss is the primary axis; RTT and
246
+ * jitter can only push the assessment to a worse level, never a better one, and
247
+ * a `"bandwidth"` encoder limitation forces at least `"fair"`. Any subset may be
248
+ * overridden via {@link PublisherOptions.connectionQualityThresholds}; the rest
249
+ * keep their defaults.
250
+ */
251
+ interface ConnectionQualityThresholds {
252
+ /** Loss ratio (`0..1`) at or above which quality is at least `"fair"`. Default `0.02`. */
253
+ fairLossRatio: number;
254
+ /** Loss ratio at or above which quality is at least `"poor"`. Default `0.05`. */
255
+ poorLossRatio: number;
256
+ /** Loss ratio at or above which quality is `"critical"`. Default `0.12`. */
257
+ criticalLossRatio: number;
258
+ /** RTT (ms) at or above which quality is at least `"fair"`. Default `300`. */
259
+ fairRttMs: number;
260
+ /** RTT (ms) at or above which quality is at least `"poor"`. Default `600`. */
261
+ poorRttMs: number;
262
+ /** RTT (ms) at or above which quality is `"critical"`. Default `1000`. */
263
+ criticalRttMs: number;
264
+ /** Jitter (ms) at or above which quality is at least `"fair"`. Default `50`. */
265
+ fairJitterMs: number;
266
+ /** Jitter (ms) at or above which quality is at least `"poor"`. Default `150`. */
267
+ poorJitterMs: number;
268
+ }
147
269
  type PublisherRecoveryState = "recovering" | "recovered" | "failed";
148
270
  type PublisherRecoveryAction = "sender_restart" | "ice_restart";
149
271
  type PublisherRecoveryFailureReason = "capture_ended" | "automatic_recovery_failed";
@@ -232,6 +354,24 @@ interface PublisherOptions {
232
354
  preferredVideoCodecs?: string[];
233
355
  /** How long to retry a dropped signaling connection to the selected gateway. Defaults to 20 seconds. */
234
356
  signalingReconnectTimeoutMs?: number;
357
+ /**
358
+ * How often, in milliseconds, to poll `RTCPeerConnection.getStats()` for
359
+ * connection-quality assessment once connected. Defaults to 2000. Set to 0 to
360
+ * disable stats polling entirely — neither {@link PublisherCallbacks.onConnectionStats}
361
+ * nor {@link PublisherCallbacks.onConnectionQualityChange} will fire.
362
+ */
363
+ connectionStatsIntervalMs?: number;
364
+ /**
365
+ * Overrides for the connection-quality classification thresholds. Any omitted
366
+ * field keeps its default. See {@link ConnectionQualityThresholds}.
367
+ */
368
+ connectionQualityThresholds?: Partial<ConnectionQualityThresholds>;
369
+ /**
370
+ * Number of consecutive worse-than-current samples required before a quality
371
+ * downgrade is committed, damping transient blips. Improvements are reported
372
+ * on the first better sample. Defaults to 2; values below 1 are treated as 1.
373
+ */
374
+ connectionQualityDebounceSamples?: number;
235
375
  /** Callbacks for lifecycle events. */
236
376
  callbacks?: PublisherCallbacks;
237
377
  }
@@ -277,6 +417,11 @@ declare class Publisher {
277
417
  private gatewayURL;
278
418
  private lastReportedICEPath;
279
419
  private watchedICETransports;
420
+ private connectionStatsTimer;
421
+ private statsSampleInFlight;
422
+ private lastStatsSample;
423
+ private currentQualityLevel;
424
+ private qualityDowngradeStreak;
280
425
  private stopped;
281
426
  private lifecycleGeneration;
282
427
  private runAbort;
@@ -459,6 +604,13 @@ declare class Publisher {
459
604
  private releaseLocalCandidateBatch;
460
605
  private applyAnswered;
461
606
  private watchSelectedICEPairChanges;
607
+ private startConnectionStatsLoop;
608
+ private stopConnectionStatsLoop;
609
+ private sampleConnectionQuality;
610
+ private buildStatsSample;
611
+ private resolveQualityThresholds;
612
+ private classifyQuality;
613
+ private updateConnectionQuality;
462
614
  private reportSelectedICEPath;
463
615
  private completeMediaRecovery;
464
616
  private failMediaRecovery;
@@ -688,4 +840,4 @@ interface CaptureMicrophoneOptions {
688
840
  */
689
841
  declare function captureMicrophone(opts?: CaptureMicrophoneOptions): Promise<MediaStream>;
690
842
 
691
- export { type AssistantTextEvent, type CaptureCameraOptions, type CaptureMicrophoneOptions, type CaptureScreenOptions, type GatewayReadyInfo, Publisher, type PublisherCallbacks, type PublisherOptions, type PublisherRecoveryAction, type PublisherRecoveryEvent, type PublisherRecoveryFailureReason, type PublisherRecoveryState, type SignalMessage, type TrackLabel, type TrackType, type TurnTransportPolicy, type UserTextResultEvent, type VideoTrackType, captureCamera, captureMicrophone, captureScreen };
843
+ export { type AssistantTextEvent, type CaptureCameraOptions, type CaptureMicrophoneOptions, type CaptureScreenOptions, type ConnectionQuality, type ConnectionQualityLevel, type ConnectionQualityThresholds, type ConnectionStatsSample, type GatewayReadyInfo, Publisher, type PublisherCallbacks, type PublisherOptions, type PublisherRecoveryAction, type PublisherRecoveryEvent, type PublisherRecoveryFailureReason, type PublisherRecoveryState, type SignalMessage, type SpeechQualityEvent, type TrackLabel, type TrackType, type TurnTransportPolicy, type UserTextResultEvent, type VideoTrackType, captureCamera, captureMicrophone, captureScreen };
package/dist/index.d.ts CHANGED
@@ -79,6 +79,11 @@ type SignalMessage = {
79
79
  track: TrackType;
80
80
  track_id?: string;
81
81
  reason?: string;
82
+ } | {
83
+ type: "speech_slow";
84
+ realtime_factor: number;
85
+ } | {
86
+ type: "speech_recovered";
82
87
  } | {
83
88
  type: "recovery_event";
84
89
  event: "recovery_started" | "recovery_retry" | "recovery_failed";
@@ -131,6 +136,32 @@ interface PublisherCallbacks {
131
136
  onUserTextResult?: (event: UserTextResultEvent) => void;
132
137
  /** Called once the explicitly requested outbound speech track arrives. */
133
138
  onSpeechTrack?: (track: MediaStreamTrack, streams: readonly MediaStream[]) => void;
139
+ /**
140
+ * Called when server-side text-to-speech generation crosses the realtime
141
+ * boundary: `degraded: true` when the TTS provider drops below realtime
142
+ * (`realtimeFactor` < 1.0), synthesizing audio slower than it plays and starving
143
+ * playout regardless of the network, and `degraded: false` when a later utterance
144
+ * climbs comfortably back above realtime. The degraded transition is raised live
145
+ * during synthesis — a long, slow utterance is reported while it is happening, not
146
+ * once it finishes. Edge-triggered — fires only on the transition, not per
147
+ * utterance, and a factor hovering at the boundary does not flap it. This is a
148
+ * distinct axis from {@link onConnectionQualityChange} (which is network health);
149
+ * react by, e.g., warning the user or offering a text fallback.
150
+ */
151
+ onSpeechQualityChange?: (event: SpeechQualityEvent) => void;
152
+ /**
153
+ * Called for every periodic connection-stats sample while connected — the raw
154
+ * feed behind {@link onConnectionQualityChange}. Fires at
155
+ * {@link PublisherOptions.connectionStatsIntervalMs}.
156
+ */
157
+ onConnectionStats?: (sample: ConnectionStatsSample) => void;
158
+ /**
159
+ * Called when the derived connection-quality level changes (including the
160
+ * first assessment after connecting). Downgrades are debounced; upgrades fire
161
+ * immediately. Use this to react to a degrading network — e.g. warn the user
162
+ * or drop a secondary track.
163
+ */
164
+ onConnectionQualityChange?: (quality: ConnectionQuality) => void;
134
165
  }
135
166
  interface AssistantTextEvent {
136
167
  utteranceId: string;
@@ -144,6 +175,97 @@ interface UserTextResultEvent {
144
175
  accepted: boolean;
145
176
  reason?: string;
146
177
  }
178
+ /**
179
+ * A change in server-side text-to-speech generation health, delivered to
180
+ * {@link PublisherCallbacks.onSpeechQualityChange}. `degraded` is `true` on the
181
+ * transition into below-realtime synthesis (`realtimeFactor` < 1.0) and `false`
182
+ * once synthesis climbs comfortably back above realtime. `realtimeFactor` (audio
183
+ * produced ÷ wall-clock to produce it) accompanies a degraded transition.
184
+ */
185
+ interface SpeechQualityEvent {
186
+ degraded: boolean;
187
+ realtimeFactor?: number;
188
+ }
189
+ /**
190
+ * A coarse assessment of the uplink to the media server, derived from periodic
191
+ * WebRTC stats. Ordered worst-last by severity: `"good"` is a healthy
192
+ * connection, `"critical"` is barely usable.
193
+ */
194
+ type ConnectionQualityLevel = "good" | "fair" | "poor" | "critical";
195
+ /**
196
+ * One periodic sample of the outbound connection's health, taken from
197
+ * `RTCPeerConnection.getStats()`. Packet loss and send bitrate are windowed over
198
+ * the interval since the previous sample (the first sample covers the session so
199
+ * far); the rest are point-in-time readings. A field is `null` when the browser
200
+ * did not report the underlying stat for this sample.
201
+ */
202
+ interface ConnectionStatsSample {
203
+ /** Monotonic clock timestamp (ms) when the sample was taken. */
204
+ timestamp: number;
205
+ /**
206
+ * Fraction of outbound RTP packets lost, in `0..1` — the primary quality
207
+ * signal. A traffic-weighted mean of each stream's loss fraction: a stream uses
208
+ * its remote `fractionLost` (its loss ratio over the last RTCP report interval)
209
+ * when present, otherwise its windowed
210
+ * `Δpacketslost / Δ(packetsSent - retransmittedPacketsSent)`. Both kinds of
211
+ * stream are combined, so a lossy stream is never dropped for lacking
212
+ * `fractionLost`.
213
+ */
214
+ lossRatio: number;
215
+ /** Round-trip time in milliseconds, or `null` if unknown. */
216
+ rttMs: number | null;
217
+ /** Inter-arrival jitter in milliseconds, or `null` if unknown. */
218
+ jitterMs: number | null;
219
+ /** ICE-estimated available outgoing bitrate in bits/sec, or `null` if unknown. */
220
+ availableOutgoingBitrate: number | null;
221
+ /** Actual send bitrate over the interval in bits/sec, or `null` if unknown. */
222
+ sendBitrate: number | null;
223
+ /**
224
+ * Why the encoder is limiting quality: `"none"`, `"cpu"`, `"bandwidth"`, or
225
+ * `"other"`. `null` when no video is being sent. `"bandwidth"` is treated as a
226
+ * degradation signal by the default classifier.
227
+ */
228
+ qualityLimitationReason: string | null;
229
+ /** Cumulative NACKs received on outbound media, or `null` if unknown. */
230
+ nackCount: number | null;
231
+ /** Cumulative PLIs received on outbound media, or `null` if unknown. */
232
+ pliCount: number | null;
233
+ }
234
+ /**
235
+ * A committed connection-quality assessment, delivered to
236
+ * {@link PublisherCallbacks.onConnectionQualityChange} whenever the level
237
+ * changes. `sample` is the reading that triggered the transition.
238
+ */
239
+ interface ConnectionQuality {
240
+ level: ConnectionQualityLevel;
241
+ sample: ConnectionStatsSample;
242
+ }
243
+ /**
244
+ * Thresholds mapping a {@link ConnectionStatsSample} to a
245
+ * {@link ConnectionQualityLevel}. Packet loss is the primary axis; RTT and
246
+ * jitter can only push the assessment to a worse level, never a better one, and
247
+ * a `"bandwidth"` encoder limitation forces at least `"fair"`. Any subset may be
248
+ * overridden via {@link PublisherOptions.connectionQualityThresholds}; the rest
249
+ * keep their defaults.
250
+ */
251
+ interface ConnectionQualityThresholds {
252
+ /** Loss ratio (`0..1`) at or above which quality is at least `"fair"`. Default `0.02`. */
253
+ fairLossRatio: number;
254
+ /** Loss ratio at or above which quality is at least `"poor"`. Default `0.05`. */
255
+ poorLossRatio: number;
256
+ /** Loss ratio at or above which quality is `"critical"`. Default `0.12`. */
257
+ criticalLossRatio: number;
258
+ /** RTT (ms) at or above which quality is at least `"fair"`. Default `300`. */
259
+ fairRttMs: number;
260
+ /** RTT (ms) at or above which quality is at least `"poor"`. Default `600`. */
261
+ poorRttMs: number;
262
+ /** RTT (ms) at or above which quality is `"critical"`. Default `1000`. */
263
+ criticalRttMs: number;
264
+ /** Jitter (ms) at or above which quality is at least `"fair"`. Default `50`. */
265
+ fairJitterMs: number;
266
+ /** Jitter (ms) at or above which quality is at least `"poor"`. Default `150`. */
267
+ poorJitterMs: number;
268
+ }
147
269
  type PublisherRecoveryState = "recovering" | "recovered" | "failed";
148
270
  type PublisherRecoveryAction = "sender_restart" | "ice_restart";
149
271
  type PublisherRecoveryFailureReason = "capture_ended" | "automatic_recovery_failed";
@@ -232,6 +354,24 @@ interface PublisherOptions {
232
354
  preferredVideoCodecs?: string[];
233
355
  /** How long to retry a dropped signaling connection to the selected gateway. Defaults to 20 seconds. */
234
356
  signalingReconnectTimeoutMs?: number;
357
+ /**
358
+ * How often, in milliseconds, to poll `RTCPeerConnection.getStats()` for
359
+ * connection-quality assessment once connected. Defaults to 2000. Set to 0 to
360
+ * disable stats polling entirely — neither {@link PublisherCallbacks.onConnectionStats}
361
+ * nor {@link PublisherCallbacks.onConnectionQualityChange} will fire.
362
+ */
363
+ connectionStatsIntervalMs?: number;
364
+ /**
365
+ * Overrides for the connection-quality classification thresholds. Any omitted
366
+ * field keeps its default. See {@link ConnectionQualityThresholds}.
367
+ */
368
+ connectionQualityThresholds?: Partial<ConnectionQualityThresholds>;
369
+ /**
370
+ * Number of consecutive worse-than-current samples required before a quality
371
+ * downgrade is committed, damping transient blips. Improvements are reported
372
+ * on the first better sample. Defaults to 2; values below 1 are treated as 1.
373
+ */
374
+ connectionQualityDebounceSamples?: number;
235
375
  /** Callbacks for lifecycle events. */
236
376
  callbacks?: PublisherCallbacks;
237
377
  }
@@ -277,6 +417,11 @@ declare class Publisher {
277
417
  private gatewayURL;
278
418
  private lastReportedICEPath;
279
419
  private watchedICETransports;
420
+ private connectionStatsTimer;
421
+ private statsSampleInFlight;
422
+ private lastStatsSample;
423
+ private currentQualityLevel;
424
+ private qualityDowngradeStreak;
280
425
  private stopped;
281
426
  private lifecycleGeneration;
282
427
  private runAbort;
@@ -459,6 +604,13 @@ declare class Publisher {
459
604
  private releaseLocalCandidateBatch;
460
605
  private applyAnswered;
461
606
  private watchSelectedICEPairChanges;
607
+ private startConnectionStatsLoop;
608
+ private stopConnectionStatsLoop;
609
+ private sampleConnectionQuality;
610
+ private buildStatsSample;
611
+ private resolveQualityThresholds;
612
+ private classifyQuality;
613
+ private updateConnectionQuality;
462
614
  private reportSelectedICEPath;
463
615
  private completeMediaRecovery;
464
616
  private failMediaRecovery;
@@ -688,4 +840,4 @@ interface CaptureMicrophoneOptions {
688
840
  */
689
841
  declare function captureMicrophone(opts?: CaptureMicrophoneOptions): Promise<MediaStream>;
690
842
 
691
- export { type AssistantTextEvent, type CaptureCameraOptions, type CaptureMicrophoneOptions, type CaptureScreenOptions, type GatewayReadyInfo, Publisher, type PublisherCallbacks, type PublisherOptions, type PublisherRecoveryAction, type PublisherRecoveryEvent, type PublisherRecoveryFailureReason, type PublisherRecoveryState, type SignalMessage, type TrackLabel, type TrackType, type TurnTransportPolicy, type UserTextResultEvent, type VideoTrackType, captureCamera, captureMicrophone, captureScreen };
843
+ export { type AssistantTextEvent, type CaptureCameraOptions, type CaptureMicrophoneOptions, type CaptureScreenOptions, type ConnectionQuality, type ConnectionQualityLevel, type ConnectionQualityThresholds, type ConnectionStatsSample, type GatewayReadyInfo, Publisher, type PublisherCallbacks, type PublisherOptions, type PublisherRecoveryAction, type PublisherRecoveryEvent, type PublisherRecoveryFailureReason, type PublisherRecoveryState, type SignalMessage, type SpeechQualityEvent, type TrackLabel, type TrackType, type TurnTransportPolicy, type UserTextResultEvent, type VideoTrackType, captureCamera, captureMicrophone, captureScreen };