@pollen-robotics/reachy-mini-sdk 1.10.0-dev.0.main.828a720 → 1.10.0-dev.0.main.9f78da7
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/lib/reachy-mini.d.ts +70 -0
- package/dist/lib/reachy-mini.d.ts.map +1 -1
- package/dist/lib/reachy-mini.js +260 -5
- package/dist/lib/reachy-mini.js.map +1 -1
- package/dist/lib/types.d.ts +19 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/host/dist/chunks/{index-lMs2sCXG.js → index-rW7LY0k3.js} +209 -118
- package/host/dist/chunks/{reachy-mini-DwiuAr8T.js → reachy-mini-DblK_lhG.js} +362 -203
- package/host/dist/embed/index.d.ts +60 -0
- package/host/dist/embed/index.d.ts.map +1 -1
- package/host/dist/entry/auto.js +1 -1
- package/host/dist/entry/embed.d.ts +5 -4
- package/host/dist/entry/embed.d.ts.map +1 -1
- package/host/dist/entry/embed.js +5 -4
- package/host/dist/index.d.ts +2 -2
- package/host/dist/index.d.ts.map +1 -1
- package/host/dist/index.js +11 -10
- package/package.json +1 -1
|
@@ -23,6 +23,9 @@ export declare class ReachyMini extends EventTarget implements ReachyMiniInstanc
|
|
|
23
23
|
private _state;
|
|
24
24
|
private _robots;
|
|
25
25
|
private _robotState;
|
|
26
|
+
private _lastPoseSeq;
|
|
27
|
+
private _lastPoseFrameAt;
|
|
28
|
+
private _poseSubRefs;
|
|
26
29
|
private readonly _preselectedRobotId;
|
|
27
30
|
private _token;
|
|
28
31
|
private _username;
|
|
@@ -43,7 +46,10 @@ export declare class ReachyMini extends EventTarget implements ReachyMiniInstanc
|
|
|
43
46
|
private _hardwareIdResolve;
|
|
44
47
|
private _volumeResolve;
|
|
45
48
|
private _micVolumeResolve;
|
|
49
|
+
private _firstWakeUpResolve;
|
|
46
50
|
private _trackedFaceResolve;
|
|
51
|
+
private _robotNameResolve;
|
|
52
|
+
private _deleteHfTokenResolve;
|
|
47
53
|
private _applyAudioConfigResolve;
|
|
48
54
|
private _readAudioParameterResolve;
|
|
49
55
|
private readonly _logSubscribers;
|
|
@@ -238,6 +244,50 @@ export declare class ReachyMini extends EventTarget implements ReachyMiniInstanc
|
|
|
238
244
|
setVolume(volume: number): Promise<number | null>;
|
|
239
245
|
getMicrophoneVolume(): Promise<number | null>;
|
|
240
246
|
setMicrophoneVolume(volume: number): Promise<number | null>;
|
|
247
|
+
/**
|
|
248
|
+
* Query whether the first wake-up setup wizard has been completed.
|
|
249
|
+
* Robot-wide, persisted on the robot. Resolves `false` when pending,
|
|
250
|
+
* `true` when done, or `null` when the channel isn't open / the daemon
|
|
251
|
+
* predates the `get_first_wake_up` command (callers should fail-open
|
|
252
|
+
* and skip the wizard on `null`).
|
|
253
|
+
*/
|
|
254
|
+
getFirstWakeUp(): Promise<boolean | null>;
|
|
255
|
+
/**
|
|
256
|
+
* Persist the first wake-up wizard completion flag on the robot.
|
|
257
|
+
* Resolves with the stored value (or `null` on channel-closed).
|
|
258
|
+
*/
|
|
259
|
+
setFirstWakeUp(isCompleted: boolean): Promise<boolean | null>;
|
|
260
|
+
/**
|
|
261
|
+
* Query the persisted robot display name. Resolves the stored name,
|
|
262
|
+
* `null` when none is set / the channel isn't open / the daemon predates
|
|
263
|
+
* the `get_robot_name` command.
|
|
264
|
+
*/
|
|
265
|
+
getRobotName(): Promise<string | null>;
|
|
266
|
+
/**
|
|
267
|
+
* Set and persist the robot display name on the robot. Resolves with the
|
|
268
|
+
* stored (trimmed) name, or `null` on error / channel-closed. Applied live
|
|
269
|
+
* by the daemon (status + central relay + mDNS), so it takes effect right
|
|
270
|
+
* away without a restart; the persisted name also overrides --robot-name
|
|
271
|
+
* on the next start.
|
|
272
|
+
*/
|
|
273
|
+
setRobotName(name: string): Promise<string | null>;
|
|
274
|
+
/**
|
|
275
|
+
* Sign this robot out of Hugging Face: asks the daemon to delete its
|
|
276
|
+
* stored HF token, which de-registers the robot from the central
|
|
277
|
+
* signaling relay (it disappears from its owner's robot list until it
|
|
278
|
+
* is set up again). Works over the WebRTC data channel, so it reaches
|
|
279
|
+
* the robot remotely (no LAN HTTP path required).
|
|
280
|
+
*
|
|
281
|
+
* Resolves `true` when the daemon acked success, `false` on a daemon
|
|
282
|
+
* error, or `null` when no ack arrives before the timeout (e.g. a
|
|
283
|
+
* daemon that predates the `delete_hf_token` command silently drops
|
|
284
|
+
* it). Rejects if the data channel isn't open. Note the sign-out
|
|
285
|
+
* drops the central relay, so the session may tear down right after
|
|
286
|
+
* the ack - callers should treat a post-call session drop as expected,
|
|
287
|
+
* and a successful sign-out may surface as `null` if teardown races
|
|
288
|
+
* ahead of the ack.
|
|
289
|
+
*/
|
|
290
|
+
signOut(): Promise<boolean | null>;
|
|
241
291
|
applyAudioConfig(config: AudioConfigEntry[], { verify }?: ApplyAudioConfigOptions): Promise<boolean>;
|
|
242
292
|
readAudioParameter(name: string): Promise<number[] | null>;
|
|
243
293
|
/**
|
|
@@ -258,6 +308,21 @@ export declare class ReachyMini extends EventTarget implements ReachyMiniInstanc
|
|
|
258
308
|
sendRaw(data: unknown): boolean;
|
|
259
309
|
subscribeLogs({ onLine, onError }: SubscribeLogsOptions): () => void;
|
|
260
310
|
requestState(): boolean;
|
|
311
|
+
/**
|
|
312
|
+
* Ask the daemon to *push* the robot state (~30 Hz) over the dedicated
|
|
313
|
+
* unreliable/unordered `pose` data channel instead of polling get_state.
|
|
314
|
+
* Fires `state` events as frames arrive. No-op against an older daemon (no
|
|
315
|
+
* pose channel) - fall back to `requestState()` polling there.
|
|
316
|
+
*
|
|
317
|
+
* Refcounted: pair every `subscribePose()` with exactly one
|
|
318
|
+
* `unsubscribePose()`. Multiple consumers share a single daemon-side
|
|
319
|
+
* subscription; the daemon only stops pushing once the last one releases.
|
|
320
|
+
* If the channel isn't open yet (or the session later reconnects), the
|
|
321
|
+
* subscription is (re-)asserted from `_checkSessionReady`.
|
|
322
|
+
*/
|
|
323
|
+
subscribePose(): boolean;
|
|
324
|
+
/** Release one pose-stream consumer; sends `unsubscribe_pose` on the last. */
|
|
325
|
+
unsubscribePose(): boolean;
|
|
261
326
|
setAudioMuted(muted: boolean): void;
|
|
262
327
|
setMicMuted(muted: boolean): void;
|
|
263
328
|
attachVideo(videoElement: HTMLVideoElement): () => void;
|
|
@@ -294,6 +359,11 @@ export declare class ReachyMini extends EventTarget implements ReachyMiniInstanc
|
|
|
294
359
|
private _handleSignalingMessage;
|
|
295
360
|
private _handleEndSession;
|
|
296
361
|
private _handlePeerMessage;
|
|
362
|
+
/**
|
|
363
|
+
* @param fromPoseStream Frame came from the pushed `pose` channel rather
|
|
364
|
+
* than the reliable control channel. Only those may refresh the state
|
|
365
|
+
* mirror while the stream is live (see the `data.state` branch).
|
|
366
|
+
*/
|
|
297
367
|
private _handleRobotMessage;
|
|
298
368
|
/** Snap video playback to live edge if buffered lag exceeds 0.5 s. */
|
|
299
369
|
private _startLatencyMonitor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reachy-mini.d.ts","sourceRoot":"","sources":["../../lib/reachy-mini.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAwBH,OAAO,KAAK,EACR,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EAEjB,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,cAAc,EACd,wBAAwB,EAExB,kBAAkB,EAClB,iBAAiB,EACjB,SAAS,EACT,UAAU,EAEV,oBAAoB,EACpB,kBAAkB,EACrB,MAAM,YAAY,CAAC;AAmBpB,kEAAkE;AAClE,MAAM,WAAW,mBAAmB;IAChC,MAAM,EAAE,aAAa,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC1C,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,sBAAsB,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"reachy-mini.d.ts","sourceRoot":"","sources":["../../lib/reachy-mini.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/reachy-mini.js
CHANGED
|
@@ -40,6 +40,35 @@ const ICE_FAILED_GRACE_MS = 1000;
|
|
|
40
40
|
* to be honest with the user.
|
|
41
41
|
*/
|
|
42
42
|
const MAX_VISIBILITY_DEFER_MS = 60_000;
|
|
43
|
+
/**
|
|
44
|
+
* How long a pushed pose frame keeps the periodic `get_state` poll on hold -
|
|
45
|
+
* both on the way out (no request is sent) and on the way back (a reply that
|
|
46
|
+
* arrives anyway doesn't touch the state mirror).
|
|
47
|
+
*
|
|
48
|
+
* Poll replies carry no `seq`, so they slip past the stale-frame guard: a
|
|
49
|
+
* reply that crosses a fresher pushed frame would rewind the very mirror the
|
|
50
|
+
* stream exists to smooth. While frames flow at ~30 Hz there is nothing left
|
|
51
|
+
* for the poll to add, so it stands down. Keying that on frame arrival rather
|
|
52
|
+
* than on `_poseSubRefs` keeps the poll running against a daemon that doesn't
|
|
53
|
+
* know `subscribe_pose`, and brings it back on its own if the stream stalls.
|
|
54
|
+
* A little over one 500 ms poll period, so a couple of dropped frames don't
|
|
55
|
+
* flip it back and forth.
|
|
56
|
+
*/
|
|
57
|
+
const POSE_STREAM_FRESH_MS = 750;
|
|
58
|
+
/**
|
|
59
|
+
* Fail-open ceiling for a single `_slotRoundtrip` request/response.
|
|
60
|
+
* Every slot command has a strict "one reply per request" contract, so
|
|
61
|
+
* a missing reply means the daemon either never got it or - crucially -
|
|
62
|
+
* predates that command entirely: an older daemon silently drops an
|
|
63
|
+
* unknown `type` and sends nothing back, which would otherwise leave the
|
|
64
|
+
* caller's promise pending forever (e.g. a newer SDK calling a command a
|
|
65
|
+
* 1.8.x daemon doesn't implement). Resolving `null` on timeout maps
|
|
66
|
+
* cleanly onto the "unsupported / failed" value every slot caller already
|
|
67
|
+
* handles. 4 s is comfortably above a WebRTC data-channel round trip on a
|
|
68
|
+
* congested phone link while still failing fast enough that a gated UI
|
|
69
|
+
* doesn't feel hung.
|
|
70
|
+
*/
|
|
71
|
+
const SLOT_ROUNDTRIP_TIMEOUT_MS = 4000;
|
|
43
72
|
export class ReachyMini extends EventTarget {
|
|
44
73
|
// ─── Config ──────────────────────────────────────────────────────────
|
|
45
74
|
_signalingUrl;
|
|
@@ -52,6 +81,19 @@ export class ReachyMini extends EventTarget {
|
|
|
52
81
|
_state = 'disconnected';
|
|
53
82
|
_robots = [];
|
|
54
83
|
_robotState = {};
|
|
84
|
+
// Highest `seq` seen on the unordered `pose` channel. Frames that arrive
|
|
85
|
+
// out of order (older seq) are dropped so a late packet can't rewind the
|
|
86
|
+
// live mirror. `null` until the first pose frame.
|
|
87
|
+
_lastPoseSeq = null;
|
|
88
|
+
// When the last pushed pose frame was applied, used to park the periodic
|
|
89
|
+
// `get_state` poll while the stream is live (see POSE_STREAM_FRESH_MS).
|
|
90
|
+
_lastPoseFrameAt = 0;
|
|
91
|
+
// Local refcount of pose-stream consumers (the 3D mirror, the wizard's
|
|
92
|
+
// move-end watcher, ...). The daemon's subscription is a per-peer boolean
|
|
93
|
+
// (not refcounted), so we only send `unsubscribe_pose` once the LAST local
|
|
94
|
+
// consumer releases - otherwise one consumer's cleanup would kill the
|
|
95
|
+
// stream for the others.
|
|
96
|
+
_poseSubRefs = 0;
|
|
55
97
|
_preselectedRobotId;
|
|
56
98
|
// ─── Auth ────────────────────────────────────────────────────────────
|
|
57
99
|
_token = null;
|
|
@@ -78,7 +120,10 @@ export class ReachyMini extends EventTarget {
|
|
|
78
120
|
_hardwareIdResolve = null;
|
|
79
121
|
_volumeResolve = null;
|
|
80
122
|
_micVolumeResolve = null;
|
|
123
|
+
_firstWakeUpResolve = null;
|
|
81
124
|
_trackedFaceResolve = null;
|
|
125
|
+
_robotNameResolve = null;
|
|
126
|
+
_deleteHfTokenResolve = null;
|
|
82
127
|
// applyAudioConfig() / readAudioParameter() share the same single-slot
|
|
83
128
|
// pattern as the volume helpers. Separate slots so the two can be
|
|
84
129
|
// in-flight concurrently without collision.
|
|
@@ -547,7 +592,35 @@ export class ReachyMini extends EventTarget {
|
|
|
547
592
|
}
|
|
548
593
|
};
|
|
549
594
|
this._pc.ondatachannel = (e) => {
|
|
550
|
-
|
|
595
|
+
const ch = e.channel;
|
|
596
|
+
// On `subscribe_pose` the daemon opens a second,
|
|
597
|
+
// unreliable/unordered channel labelled "pose" that *pushes*
|
|
598
|
+
// the robot state at ~30 Hz (see media_server
|
|
599
|
+
// `_setup_pose_channel`), so this can fire mid-session. It
|
|
600
|
+
// carries the same `{state:{...}}` envelope as a get_state
|
|
601
|
+
// reply, so we route it through the same handler - but it
|
|
602
|
+
// must NOT gate session readiness (that's the reliable
|
|
603
|
+
// control channel's job) nor become `_dc` (commands must
|
|
604
|
+
// never ride the lossy channel).
|
|
605
|
+
if (ch.label === 'pose') {
|
|
606
|
+
// Fresh channel (new session or daemon restart): the
|
|
607
|
+
// daemon's seq counter may have reset, so forget the old
|
|
608
|
+
// high-water mark or we'd drop every new frame.
|
|
609
|
+
this._lastPoseSeq = null;
|
|
610
|
+
ch.onmessage = (ev) => {
|
|
611
|
+
const msg = JSON.parse(ev.data);
|
|
612
|
+
// Drop stale/reordered frames (unordered channel).
|
|
613
|
+
if (typeof msg.seq === 'number') {
|
|
614
|
+
if (this._lastPoseSeq !== null && msg.seq <= this._lastPoseSeq)
|
|
615
|
+
return;
|
|
616
|
+
this._lastPoseSeq = msg.seq;
|
|
617
|
+
}
|
|
618
|
+
this._lastPoseFrameAt = Date.now();
|
|
619
|
+
this._handleRobotMessage(msg, true);
|
|
620
|
+
};
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
this._dc = ch;
|
|
551
624
|
this._dc.onopen = () => {
|
|
552
625
|
this._dcOpen = true;
|
|
553
626
|
this._checkSessionReady();
|
|
@@ -611,6 +684,10 @@ export class ReachyMini extends EventTarget {
|
|
|
611
684
|
this._micVolumeResolve(null);
|
|
612
685
|
this._micVolumeResolve = null;
|
|
613
686
|
}
|
|
687
|
+
if (this._firstWakeUpResolve) {
|
|
688
|
+
this._firstWakeUpResolve(null);
|
|
689
|
+
this._firstWakeUpResolve = null;
|
|
690
|
+
}
|
|
614
691
|
if (this._trackedFaceResolve) {
|
|
615
692
|
this._trackedFaceResolve(null);
|
|
616
693
|
this._trackedFaceResolve = null;
|
|
@@ -623,6 +700,14 @@ export class ReachyMini extends EventTarget {
|
|
|
623
700
|
this._readAudioParameterResolve(null);
|
|
624
701
|
this._readAudioParameterResolve = null;
|
|
625
702
|
}
|
|
703
|
+
if (this._robotNameResolve) {
|
|
704
|
+
this._robotNameResolve(null);
|
|
705
|
+
this._robotNameResolve = null;
|
|
706
|
+
}
|
|
707
|
+
if (this._deleteHfTokenResolve) {
|
|
708
|
+
this._deleteHfTokenResolve(null);
|
|
709
|
+
this._deleteHfTokenResolve = null;
|
|
710
|
+
}
|
|
626
711
|
this._logSubscribers.clear();
|
|
627
712
|
this._updateProgressSubscribers.clear();
|
|
628
713
|
this._rejectPendingMotionCompletions(new Error('Session stopped'));
|
|
@@ -691,6 +776,10 @@ export class ReachyMini extends EventTarget {
|
|
|
691
776
|
this._micVolumeResolve(null);
|
|
692
777
|
this._micVolumeResolve = null;
|
|
693
778
|
}
|
|
779
|
+
if (this._firstWakeUpResolve) {
|
|
780
|
+
this._firstWakeUpResolve(null);
|
|
781
|
+
this._firstWakeUpResolve = null;
|
|
782
|
+
}
|
|
694
783
|
if (this._trackedFaceResolve) {
|
|
695
784
|
this._trackedFaceResolve(null);
|
|
696
785
|
this._trackedFaceResolve = null;
|
|
@@ -703,6 +792,14 @@ export class ReachyMini extends EventTarget {
|
|
|
703
792
|
this._readAudioParameterResolve(null);
|
|
704
793
|
this._readAudioParameterResolve = null;
|
|
705
794
|
}
|
|
795
|
+
if (this._robotNameResolve) {
|
|
796
|
+
this._robotNameResolve(null);
|
|
797
|
+
this._robotNameResolve = null;
|
|
798
|
+
}
|
|
799
|
+
if (this._deleteHfTokenResolve) {
|
|
800
|
+
this._deleteHfTokenResolve(null);
|
|
801
|
+
this._deleteHfTokenResolve = null;
|
|
802
|
+
}
|
|
706
803
|
this._logSubscribers.clear();
|
|
707
804
|
this._updateProgressSubscribers.clear();
|
|
708
805
|
this._rejectPendingMotionCompletions(new Error('Disconnected'));
|
|
@@ -1178,6 +1275,66 @@ export class ReachyMini extends EventTarget {
|
|
|
1178
1275
|
setMicrophoneVolume(volume) {
|
|
1179
1276
|
return this._slotRoundtrip(() => this._micVolumeResolve, (next) => { this._micVolumeResolve = next; }, { type: 'set_microphone_volume', volume: clampVolume(volume) });
|
|
1180
1277
|
}
|
|
1278
|
+
/**
|
|
1279
|
+
* Query whether the first wake-up setup wizard has been completed.
|
|
1280
|
+
* Robot-wide, persisted on the robot. Resolves `false` when pending,
|
|
1281
|
+
* `true` when done, or `null` when the channel isn't open / the daemon
|
|
1282
|
+
* predates the `get_first_wake_up` command (callers should fail-open
|
|
1283
|
+
* and skip the wizard on `null`).
|
|
1284
|
+
*/
|
|
1285
|
+
getFirstWakeUp() {
|
|
1286
|
+
// Fail-open, so this never rejects: the wizard gate runs right after
|
|
1287
|
+
// connect, which is exactly when the channel may not be open yet.
|
|
1288
|
+
if (!this._dc || this._dc.readyState !== 'open')
|
|
1289
|
+
return Promise.resolve(null);
|
|
1290
|
+
return this._slotRoundtrip(() => this._firstWakeUpResolve, (next) => { this._firstWakeUpResolve = next; }, { type: 'get_first_wake_up' });
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Persist the first wake-up wizard completion flag on the robot.
|
|
1294
|
+
* Resolves with the stored value (or `null` on channel-closed).
|
|
1295
|
+
*/
|
|
1296
|
+
setFirstWakeUp(isCompleted) {
|
|
1297
|
+
if (!this._dc || this._dc.readyState !== 'open')
|
|
1298
|
+
return Promise.resolve(null);
|
|
1299
|
+
return this._slotRoundtrip(() => this._firstWakeUpResolve, (next) => { this._firstWakeUpResolve = next; }, { type: 'set_first_wake_up', is_completed: isCompleted });
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Query the persisted robot display name. Resolves the stored name,
|
|
1303
|
+
* `null` when none is set / the channel isn't open / the daemon predates
|
|
1304
|
+
* the `get_robot_name` command.
|
|
1305
|
+
*/
|
|
1306
|
+
getRobotName() {
|
|
1307
|
+
return this._slotRoundtrip(() => this._robotNameResolve, (next) => { this._robotNameResolve = next; }, { type: 'get_robot_name' });
|
|
1308
|
+
}
|
|
1309
|
+
/**
|
|
1310
|
+
* Set and persist the robot display name on the robot. Resolves with the
|
|
1311
|
+
* stored (trimmed) name, or `null` on error / channel-closed. Applied live
|
|
1312
|
+
* by the daemon (status + central relay + mDNS), so it takes effect right
|
|
1313
|
+
* away without a restart; the persisted name also overrides --robot-name
|
|
1314
|
+
* on the next start.
|
|
1315
|
+
*/
|
|
1316
|
+
setRobotName(name) {
|
|
1317
|
+
return this._slotRoundtrip(() => this._robotNameResolve, (next) => { this._robotNameResolve = next; }, { type: 'set_robot_name', name });
|
|
1318
|
+
}
|
|
1319
|
+
/**
|
|
1320
|
+
* Sign this robot out of Hugging Face: asks the daemon to delete its
|
|
1321
|
+
* stored HF token, which de-registers the robot from the central
|
|
1322
|
+
* signaling relay (it disappears from its owner's robot list until it
|
|
1323
|
+
* is set up again). Works over the WebRTC data channel, so it reaches
|
|
1324
|
+
* the robot remotely (no LAN HTTP path required).
|
|
1325
|
+
*
|
|
1326
|
+
* Resolves `true` when the daemon acked success, `false` on a daemon
|
|
1327
|
+
* error, or `null` when no ack arrives before the timeout (e.g. a
|
|
1328
|
+
* daemon that predates the `delete_hf_token` command silently drops
|
|
1329
|
+
* it). Rejects if the data channel isn't open. Note the sign-out
|
|
1330
|
+
* drops the central relay, so the session may tear down right after
|
|
1331
|
+
* the ack - callers should treat a post-call session drop as expected,
|
|
1332
|
+
* and a successful sign-out may surface as `null` if teardown races
|
|
1333
|
+
* ahead of the ack.
|
|
1334
|
+
*/
|
|
1335
|
+
signOut() {
|
|
1336
|
+
return this._slotRoundtrip(() => this._deleteHfTokenResolve, (next) => { this._deleteHfTokenResolve = next; }, { type: 'delete_hf_token' });
|
|
1337
|
+
}
|
|
1181
1338
|
applyAudioConfig(config, { verify = true } = {}) {
|
|
1182
1339
|
return this._slotRoundtrip(() => this._applyAudioConfigResolve, (next) => { this._applyAudioConfigResolve = next; }, { type: 'apply_audio_config', config, verify }).then((v) => v === true);
|
|
1183
1340
|
}
|
|
@@ -1207,7 +1364,29 @@ export class ReachyMini extends EventTarget {
|
|
|
1207
1364
|
const prev = getSlot();
|
|
1208
1365
|
if (prev)
|
|
1209
1366
|
prev(null);
|
|
1210
|
-
|
|
1367
|
+
let timer;
|
|
1368
|
+
// Single settle path shared by the daemon response, supersession
|
|
1369
|
+
// by a newer call, and the fail-open timeout below. It clears the
|
|
1370
|
+
// timer once and detaches itself from the slot only if it's still
|
|
1371
|
+
// the current occupant, so a stale settle (timed-out or superseded)
|
|
1372
|
+
// can't clear a newer call's slot registration. The message handler
|
|
1373
|
+
// stores `settle` (not `resolve`), so every response route funnels
|
|
1374
|
+
// through here.
|
|
1375
|
+
// Note: slots are keyed by command type, not request id, so this
|
|
1376
|
+
// does not prevent a genuinely late daemon reply from being routed
|
|
1377
|
+
// to a newer same-command caller — that cross-talk is inherent to
|
|
1378
|
+
// the single-flight slot design and unchanged here.
|
|
1379
|
+
const settle = (v) => {
|
|
1380
|
+
if (timer !== undefined) {
|
|
1381
|
+
clearTimeout(timer);
|
|
1382
|
+
timer = undefined;
|
|
1383
|
+
}
|
|
1384
|
+
if (getSlot() === settle)
|
|
1385
|
+
setSlot(null);
|
|
1386
|
+
resolve(v);
|
|
1387
|
+
};
|
|
1388
|
+
setSlot(settle);
|
|
1389
|
+
timer = setTimeout(() => settle(null), SLOT_ROUNDTRIP_TIMEOUT_MS);
|
|
1211
1390
|
this._sendCommand(command);
|
|
1212
1391
|
});
|
|
1213
1392
|
}
|
|
@@ -1237,6 +1416,30 @@ export class ReachyMini extends EventTarget {
|
|
|
1237
1416
|
requestState() {
|
|
1238
1417
|
return this._sendCommand({ type: 'get_state' });
|
|
1239
1418
|
}
|
|
1419
|
+
/**
|
|
1420
|
+
* Ask the daemon to *push* the robot state (~30 Hz) over the dedicated
|
|
1421
|
+
* unreliable/unordered `pose` data channel instead of polling get_state.
|
|
1422
|
+
* Fires `state` events as frames arrive. No-op against an older daemon (no
|
|
1423
|
+
* pose channel) - fall back to `requestState()` polling there.
|
|
1424
|
+
*
|
|
1425
|
+
* Refcounted: pair every `subscribePose()` with exactly one
|
|
1426
|
+
* `unsubscribePose()`. Multiple consumers share a single daemon-side
|
|
1427
|
+
* subscription; the daemon only stops pushing once the last one releases.
|
|
1428
|
+
* If the channel isn't open yet (or the session later reconnects), the
|
|
1429
|
+
* subscription is (re-)asserted from `_checkSessionReady`.
|
|
1430
|
+
*/
|
|
1431
|
+
subscribePose() {
|
|
1432
|
+
this._poseSubRefs++;
|
|
1433
|
+
return this._sendCommand({ type: 'subscribe_pose' });
|
|
1434
|
+
}
|
|
1435
|
+
/** Release one pose-stream consumer; sends `unsubscribe_pose` on the last. */
|
|
1436
|
+
unsubscribePose() {
|
|
1437
|
+
if (this._poseSubRefs > 0)
|
|
1438
|
+
this._poseSubRefs--;
|
|
1439
|
+
if (this._poseSubRefs > 0)
|
|
1440
|
+
return true; // still wanted by another consumer
|
|
1441
|
+
return this._sendCommand({ type: 'unsubscribe_pose' });
|
|
1442
|
+
}
|
|
1240
1443
|
// ─── Audio ───────────────────────────────────────────────────────────
|
|
1241
1444
|
setAudioMuted(muted) {
|
|
1242
1445
|
this._audioMuted = muted;
|
|
@@ -1617,7 +1820,22 @@ export class ReachyMini extends EventTarget {
|
|
|
1617
1820
|
if (this._iceConnected && this._dcOpen && this._sessionResolve) {
|
|
1618
1821
|
this._state = 'streaming';
|
|
1619
1822
|
this.requestState();
|
|
1620
|
-
|
|
1823
|
+
// Re-assert a pose subscription that was requested before the data
|
|
1824
|
+
// channel was open, or lost on reconnect (a fresh peer starts
|
|
1825
|
+
// unsubscribed on the daemon). Sent raw so it doesn't touch the
|
|
1826
|
+
// local refcount, which already reflects the live consumer count.
|
|
1827
|
+
if (this._poseSubRefs > 0)
|
|
1828
|
+
this._sendCommand({ type: 'subscribe_pose' });
|
|
1829
|
+
// A fresh session has received no pose frame yet, so a timestamp
|
|
1830
|
+
// left over from the previous one must not hold off the poll.
|
|
1831
|
+
this._lastPoseFrameAt = 0;
|
|
1832
|
+
this._stateRefreshInterval = setInterval(() => {
|
|
1833
|
+
// Skip while the pose stream is already feeding state; see
|
|
1834
|
+
// POSE_STREAM_FRESH_MS.
|
|
1835
|
+
if (Date.now() - this._lastPoseFrameAt < POSE_STREAM_FRESH_MS)
|
|
1836
|
+
return;
|
|
1837
|
+
this.requestState();
|
|
1838
|
+
}, 500);
|
|
1621
1839
|
this._emit('streaming', { sessionId: this._sessionId, robotId: this._selectedRobotId });
|
|
1622
1840
|
this._sessionResolve();
|
|
1623
1841
|
this._sessionResolve = null;
|
|
@@ -1761,7 +1979,12 @@ export class ReachyMini extends EventTarget {
|
|
|
1761
1979
|
this._emit('error', { source: 'webrtc', error: e });
|
|
1762
1980
|
}
|
|
1763
1981
|
}
|
|
1764
|
-
|
|
1982
|
+
/**
|
|
1983
|
+
* @param fromPoseStream Frame came from the pushed `pose` channel rather
|
|
1984
|
+
* than the reliable control channel. Only those may refresh the state
|
|
1985
|
+
* mirror while the stream is live (see the `data.state` branch).
|
|
1986
|
+
*/
|
|
1987
|
+
_handleRobotMessage(data, fromPoseStream = false) {
|
|
1765
1988
|
// JSON-RPC frames (app control surface) are handled separately from
|
|
1766
1989
|
// the legacy {command|type} robot messages that share this channel.
|
|
1767
1990
|
if (data.jsonrpc === '2.0') {
|
|
@@ -1792,6 +2015,27 @@ export class ReachyMini extends EventTarget {
|
|
|
1792
2015
|
}
|
|
1793
2016
|
return;
|
|
1794
2017
|
}
|
|
2018
|
+
if (data.command === 'get_first_wake_up' || data.command === 'set_first_wake_up') {
|
|
2019
|
+
if (this._firstWakeUpResolve) {
|
|
2020
|
+
this._firstWakeUpResolve(data.status === 'error' ? null : !!data.is_completed);
|
|
2021
|
+
this._firstWakeUpResolve = null;
|
|
2022
|
+
}
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
2025
|
+
if (data.command === 'get_robot_name' || data.command === 'set_robot_name') {
|
|
2026
|
+
if (this._robotNameResolve) {
|
|
2027
|
+
this._robotNameResolve(data.status === 'error' ? null : (data.name ?? null));
|
|
2028
|
+
this._robotNameResolve = null;
|
|
2029
|
+
}
|
|
2030
|
+
return;
|
|
2031
|
+
}
|
|
2032
|
+
if (data.command === 'delete_hf_token') {
|
|
2033
|
+
if (this._deleteHfTokenResolve) {
|
|
2034
|
+
this._deleteHfTokenResolve(data.status === 'error' ? false : true);
|
|
2035
|
+
this._deleteHfTokenResolve = null;
|
|
2036
|
+
}
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
1795
2039
|
if (data.command === 'apply_audio_config') {
|
|
1796
2040
|
if (this._applyAudioConfigResolve) {
|
|
1797
2041
|
this._applyAudioConfigResolve(data.error ? false : !!data.applied);
|
|
@@ -1888,7 +2132,18 @@ export class ReachyMini extends EventTarget {
|
|
|
1888
2132
|
}
|
|
1889
2133
|
return;
|
|
1890
2134
|
}
|
|
1891
|
-
|
|
2135
|
+
// Only the stream may write the mirror while the stream is live. The
|
|
2136
|
+
// poll stands down in that case (see POSE_STREAM_FRESH_MS), but it
|
|
2137
|
+
// can't unsend a request already in flight: `get_state` rides the
|
|
2138
|
+
// reliable channel, so its reply queues behind whatever else is on it
|
|
2139
|
+
// - a `upload_move_*` burst, typically - and can land hundreds of ms
|
|
2140
|
+
// after the snapshot it carries. Having no `seq`, it slips past the
|
|
2141
|
+
// stale-frame guard and rewinds every consumer to a pose from before
|
|
2142
|
+
// the upload, until the next pushed frame puts them back. That reads
|
|
2143
|
+
// as a one-frame flick to the pre-move pose right as an animation
|
|
2144
|
+
// starts. Nothing is lost by dropping it: pushed frames carry the same
|
|
2145
|
+
// fields (daemon-side `build_state_dict` feeds both).
|
|
2146
|
+
if (data.state && (fromPoseStream || Date.now() - this._lastPoseFrameAt >= POSE_STREAM_FRESH_MS)) {
|
|
1892
2147
|
const s = data.state;
|
|
1893
2148
|
if (s.head_pose)
|
|
1894
2149
|
this._robotState.head = s.head_pose.flat();
|