Spaces:
Sleeping
Sleeping
Update
Browse files- client/js/dist/index.d.ts +8 -0
- client/js/dist/robotics/consumer.d.ts +21 -0
- client/js/dist/robotics/core.d.ts +43 -0
- client/js/dist/robotics/factory.d.ts +18 -0
- client/js/dist/robotics/index.d.ts +10 -0
- client/js/dist/robotics/producer.d.ts +21 -0
- client/js/dist/robotics/types.d.ts +127 -0
- client/js/dist/video/consumer.d.ts +52 -0
- client/js/dist/video/core.d.ts +61 -0
- client/js/dist/video/factory.d.ts +18 -0
- client/js/dist/video/index.d.ts +10 -0
- client/js/dist/video/producer.d.ts +36 -0
- client/js/dist/video/types.d.ts +249 -0
- client/js/tsconfig.json +0 -1
client/js/dist/index.d.ts
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* LeRobot Arena Client Library - TypeScript/JavaScript
|
3 |
+
*
|
4 |
+
* Main entry point for the robotics client library.
|
5 |
+
*/
|
6 |
+
export * as robotics from './robotics/index.js';
|
7 |
+
export * as video from './video/index.js';
|
8 |
+
export declare const VERSION = "1.0.0";
|
client/js/dist/robotics/consumer.d.ts
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Consumer client for receiving robot commands in LeRobot Arena
|
3 |
+
*/
|
4 |
+
import { RoboticsClientCore } from './core.js';
|
5 |
+
import type { WebSocketMessage, ClientOptions, JointUpdateCallback, StateSyncCallback } from './types.js';
|
6 |
+
export declare class RoboticsConsumer extends RoboticsClientCore {
|
7 |
+
private onStateSyncCallback;
|
8 |
+
private onJointUpdateCallback;
|
9 |
+
constructor(baseUrl?: string, options?: ClientOptions);
|
10 |
+
connect(workspaceId: string, roomId: string, participantId?: string): Promise<boolean>;
|
11 |
+
getStateSyncAsync(): Promise<Record<string, number>>;
|
12 |
+
onStateSync(callback: StateSyncCallback): void;
|
13 |
+
onJointUpdate(callback: JointUpdateCallback): void;
|
14 |
+
protected handleRoleSpecificMessage(message: WebSocketMessage): void;
|
15 |
+
private handleStateSync;
|
16 |
+
private handleJointUpdate;
|
17 |
+
/**
|
18 |
+
* Create a consumer and automatically connect to a room
|
19 |
+
*/
|
20 |
+
static createAndConnect(workspaceId: string, roomId: string, baseUrl?: string, participantId?: string): Promise<RoboticsConsumer>;
|
21 |
+
}
|
client/js/dist/robotics/core.d.ts
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Core robotics client for LeRobot Arena
|
3 |
+
* Base class providing REST API and WebSocket functionality
|
4 |
+
*/
|
5 |
+
import { EventEmitter } from 'eventemitter3';
|
6 |
+
import type { ParticipantRole, RoomInfo, RoomState, ConnectionInfo, WebSocketMessage, ClientOptions, ErrorCallback, ConnectedCallback, DisconnectedCallback } from './types.js';
|
7 |
+
export declare class RoboticsClientCore extends EventEmitter {
|
8 |
+
protected baseUrl: string;
|
9 |
+
protected apiBase: string;
|
10 |
+
protected websocket: WebSocket | null;
|
11 |
+
protected workspaceId: string | null;
|
12 |
+
protected roomId: string | null;
|
13 |
+
protected role: ParticipantRole | null;
|
14 |
+
protected participantId: string | null;
|
15 |
+
protected connected: boolean;
|
16 |
+
protected options: ClientOptions;
|
17 |
+
protected onErrorCallback: ErrorCallback | null;
|
18 |
+
protected onConnectedCallback: ConnectedCallback | null;
|
19 |
+
protected onDisconnectedCallback: DisconnectedCallback | null;
|
20 |
+
constructor(baseUrl?: string, options?: ClientOptions);
|
21 |
+
listRooms(workspaceId: string): Promise<RoomInfo[]>;
|
22 |
+
createRoom(workspaceId?: string, roomId?: string): Promise<{
|
23 |
+
workspaceId: string;
|
24 |
+
roomId: string;
|
25 |
+
}>;
|
26 |
+
deleteRoom(workspaceId: string, roomId: string): Promise<boolean>;
|
27 |
+
getRoomState(workspaceId: string, roomId: string): Promise<RoomState>;
|
28 |
+
getRoomInfo(workspaceId: string, roomId: string): Promise<RoomInfo>;
|
29 |
+
connectToRoom(workspaceId: string, roomId: string, role: ParticipantRole, participantId?: string): Promise<boolean>;
|
30 |
+
disconnect(): Promise<void>;
|
31 |
+
protected sendJoinMessage(): void;
|
32 |
+
protected handleMessage(message: WebSocketMessage): void;
|
33 |
+
protected handleRoleSpecificMessage(message: WebSocketMessage): void;
|
34 |
+
protected handleError(errorMessage: string): void;
|
35 |
+
sendHeartbeat(): Promise<void>;
|
36 |
+
isConnected(): boolean;
|
37 |
+
getConnectionInfo(): ConnectionInfo;
|
38 |
+
onError(callback: ErrorCallback): void;
|
39 |
+
onConnected(callback: ConnectedCallback): void;
|
40 |
+
onDisconnected(callback: DisconnectedCallback): void;
|
41 |
+
private fetchApi;
|
42 |
+
protected generateWorkspaceId(): string;
|
43 |
+
}
|
client/js/dist/robotics/factory.d.ts
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Factory functions for creating LeRobot Arena robotics clients
|
3 |
+
*/
|
4 |
+
import { RoboticsProducer } from './producer.js';
|
5 |
+
import { RoboticsConsumer } from './consumer.js';
|
6 |
+
import type { ParticipantRole, ClientOptions } from './types.js';
|
7 |
+
/**
|
8 |
+
* Factory function to create the appropriate client based on role
|
9 |
+
*/
|
10 |
+
export declare function createClient(role: ParticipantRole, baseUrl?: string, options?: ClientOptions): RoboticsProducer | RoboticsConsumer;
|
11 |
+
/**
|
12 |
+
* Create and connect a producer client
|
13 |
+
*/
|
14 |
+
export declare function createProducerClient(baseUrl?: string, workspaceId?: string, roomId?: string, participantId?: string, options?: ClientOptions): Promise<RoboticsProducer>;
|
15 |
+
/**
|
16 |
+
* Create and connect a consumer client
|
17 |
+
*/
|
18 |
+
export declare function createConsumerClient(workspaceId: string, roomId: string, baseUrl?: string, participantId?: string, options?: ClientOptions): Promise<RoboticsConsumer>;
|
client/js/dist/robotics/index.d.ts
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* LeRobot Arena Robotics Client - Main Module
|
3 |
+
*
|
4 |
+
* TypeScript/JavaScript client for robotics control and monitoring
|
5 |
+
*/
|
6 |
+
export { RoboticsClientCore } from './core.js';
|
7 |
+
export { RoboticsProducer } from './producer.js';
|
8 |
+
export { RoboticsConsumer } from './consumer.js';
|
9 |
+
export * from './types.js';
|
10 |
+
export { createProducerClient, createConsumerClient, createClient } from './factory.js';
|
client/js/dist/robotics/producer.d.ts
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Producer client for controlling robots in LeRobot Arena
|
3 |
+
*/
|
4 |
+
import { RoboticsClientCore } from './core.js';
|
5 |
+
import type { JointData, WebSocketMessage, ClientOptions } from './types.js';
|
6 |
+
export declare class RoboticsProducer extends RoboticsClientCore {
|
7 |
+
constructor(baseUrl?: string, options?: ClientOptions);
|
8 |
+
connect(workspaceId: string, roomId: string, participantId?: string): Promise<boolean>;
|
9 |
+
sendJointUpdate(joints: JointData[]): Promise<void>;
|
10 |
+
sendStateSync(state: Record<string, number>): Promise<void>;
|
11 |
+
sendEmergencyStop(reason?: string): Promise<void>;
|
12 |
+
protected handleRoleSpecificMessage(message: WebSocketMessage): void;
|
13 |
+
/**
|
14 |
+
* Create a room and automatically connect as producer
|
15 |
+
*/
|
16 |
+
static createAndConnect(baseUrl?: string, workspaceId?: string, roomId?: string, participantId?: string): Promise<RoboticsProducer>;
|
17 |
+
/**
|
18 |
+
* Get the current room ID (useful when auto-created)
|
19 |
+
*/
|
20 |
+
get currentRoomId(): string | null;
|
21 |
+
}
|
client/js/dist/robotics/types.d.ts
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Type definitions for LeRobot Arena Robotics Client
|
3 |
+
*/
|
4 |
+
export type ParticipantRole = 'producer' | 'consumer';
|
5 |
+
export type MessageType = 'joint_update' | 'state_sync' | 'heartbeat' | 'heartbeat_ack' | 'emergency_stop' | 'joined' | 'error';
|
6 |
+
export interface JointData {
|
7 |
+
name: string;
|
8 |
+
value: number;
|
9 |
+
speed?: number;
|
10 |
+
}
|
11 |
+
export interface RoomInfo {
|
12 |
+
id: string;
|
13 |
+
workspace_id: string;
|
14 |
+
participants: {
|
15 |
+
producer: string | null;
|
16 |
+
consumers: string[];
|
17 |
+
total: number;
|
18 |
+
};
|
19 |
+
joints_count: number;
|
20 |
+
has_producer?: boolean;
|
21 |
+
active_consumers?: number;
|
22 |
+
}
|
23 |
+
export interface RoomState {
|
24 |
+
room_id: string;
|
25 |
+
workspace_id: string;
|
26 |
+
joints: Record<string, number>;
|
27 |
+
participants: {
|
28 |
+
producer: string | null;
|
29 |
+
consumers: string[];
|
30 |
+
total: number;
|
31 |
+
};
|
32 |
+
timestamp: string;
|
33 |
+
}
|
34 |
+
export interface ConnectionInfo {
|
35 |
+
connected: boolean;
|
36 |
+
workspace_id: string | null;
|
37 |
+
room_id: string | null;
|
38 |
+
role: ParticipantRole | null;
|
39 |
+
participant_id: string | null;
|
40 |
+
base_url: string;
|
41 |
+
}
|
42 |
+
export interface BaseMessage {
|
43 |
+
type: MessageType;
|
44 |
+
timestamp?: string;
|
45 |
+
}
|
46 |
+
export interface JointUpdateMessage extends BaseMessage {
|
47 |
+
type: 'joint_update';
|
48 |
+
data: JointData[];
|
49 |
+
source?: string;
|
50 |
+
}
|
51 |
+
export interface StateSyncMessage extends BaseMessage {
|
52 |
+
type: 'state_sync';
|
53 |
+
data: Record<string, number>;
|
54 |
+
}
|
55 |
+
export interface HeartbeatMessage extends BaseMessage {
|
56 |
+
type: 'heartbeat';
|
57 |
+
}
|
58 |
+
export interface HeartbeatAckMessage extends BaseMessage {
|
59 |
+
type: 'heartbeat_ack';
|
60 |
+
}
|
61 |
+
export interface EmergencyStopMessage extends BaseMessage {
|
62 |
+
type: 'emergency_stop';
|
63 |
+
reason: string;
|
64 |
+
source?: string;
|
65 |
+
}
|
66 |
+
export interface JoinedMessage extends BaseMessage {
|
67 |
+
type: 'joined';
|
68 |
+
room_id: string;
|
69 |
+
role: ParticipantRole;
|
70 |
+
}
|
71 |
+
export interface ErrorMessage extends BaseMessage {
|
72 |
+
type: 'error';
|
73 |
+
message: string;
|
74 |
+
}
|
75 |
+
export type WebSocketMessage = JointUpdateMessage | StateSyncMessage | HeartbeatMessage | HeartbeatAckMessage | EmergencyStopMessage | JoinedMessage | ErrorMessage;
|
76 |
+
export interface ApiResponse<T = unknown> {
|
77 |
+
success: boolean;
|
78 |
+
data?: T;
|
79 |
+
error?: string;
|
80 |
+
message?: string;
|
81 |
+
}
|
82 |
+
export interface ListRoomsResponse {
|
83 |
+
success: boolean;
|
84 |
+
workspace_id: string;
|
85 |
+
rooms: RoomInfo[];
|
86 |
+
total: number;
|
87 |
+
}
|
88 |
+
export interface CreateRoomResponse {
|
89 |
+
success: boolean;
|
90 |
+
workspace_id: string;
|
91 |
+
room_id: string;
|
92 |
+
message: string;
|
93 |
+
}
|
94 |
+
export interface GetRoomResponse {
|
95 |
+
success: boolean;
|
96 |
+
workspace_id: string;
|
97 |
+
room: RoomInfo;
|
98 |
+
}
|
99 |
+
export interface GetRoomStateResponse {
|
100 |
+
success: boolean;
|
101 |
+
workspace_id: string;
|
102 |
+
state: RoomState;
|
103 |
+
}
|
104 |
+
export interface DeleteRoomResponse {
|
105 |
+
success: boolean;
|
106 |
+
workspace_id: string;
|
107 |
+
message: string;
|
108 |
+
}
|
109 |
+
export interface CreateRoomRequest {
|
110 |
+
room_id?: string;
|
111 |
+
workspace_id?: string;
|
112 |
+
}
|
113 |
+
export interface JoinMessage {
|
114 |
+
participant_id: string;
|
115 |
+
role: ParticipantRole;
|
116 |
+
}
|
117 |
+
export type JointUpdateCallback = (joints: JointData[]) => void;
|
118 |
+
export type StateSyncCallback = (state: Record<string, number>) => void;
|
119 |
+
export type ErrorCallback = (error: string) => void;
|
120 |
+
export type ConnectedCallback = () => void;
|
121 |
+
export type DisconnectedCallback = () => void;
|
122 |
+
export interface ClientOptions {
|
123 |
+
base_url?: string;
|
124 |
+
timeout?: number;
|
125 |
+
reconnect_attempts?: number;
|
126 |
+
heartbeat_interval?: number;
|
127 |
+
}
|
client/js/dist/video/consumer.d.ts
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Consumer client for receiving video streams in LeRobot Arena
|
3 |
+
*/
|
4 |
+
import { VideoClientCore } from './core.js';
|
5 |
+
import type { WebSocketMessage, ClientOptions, WebRTCStats, FrameUpdateCallback, VideoConfigUpdateCallback, StreamStartedCallback, StreamStoppedCallback, RecoveryTriggeredCallback, StatusUpdateCallback, StreamStatsCallback, WebRTCOfferMessage } from './types.js';
|
6 |
+
export declare class VideoConsumer extends VideoClientCore {
|
7 |
+
private onFrameUpdateCallback;
|
8 |
+
private onVideoConfigUpdateCallback;
|
9 |
+
private onStreamStartedCallback;
|
10 |
+
private onStreamStoppedCallback;
|
11 |
+
private onRecoveryTriggeredCallback;
|
12 |
+
private onStatusUpdateCallback;
|
13 |
+
private onStreamStatsCallback;
|
14 |
+
private iceCandidateQueue;
|
15 |
+
private hasRemoteDescription;
|
16 |
+
constructor(baseUrl?: string, options?: ClientOptions);
|
17 |
+
connect(workspaceId: string, roomId: string, participantId?: string): Promise<boolean>;
|
18 |
+
startReceiving(): Promise<void>;
|
19 |
+
stopReceiving(): Promise<void>;
|
20 |
+
handleWebRTCOffer(message: WebRTCOfferMessage): Promise<void>;
|
21 |
+
private handleWebRTCIce;
|
22 |
+
private processQueuedIceCandidates;
|
23 |
+
createPeerConnection(): RTCPeerConnection;
|
24 |
+
private sendIceCandidateToProducer;
|
25 |
+
private handleStreamStarted;
|
26 |
+
onFrameUpdate(callback: FrameUpdateCallback): void;
|
27 |
+
onVideoConfigUpdate(callback: VideoConfigUpdateCallback): void;
|
28 |
+
onStreamStarted(callback: StreamStartedCallback): void;
|
29 |
+
onStreamStopped(callback: StreamStoppedCallback): void;
|
30 |
+
onRecoveryTriggered(callback: RecoveryTriggeredCallback): void;
|
31 |
+
onStatusUpdate(callback: StatusUpdateCallback): void;
|
32 |
+
onStreamStats(callback: StreamStatsCallback): void;
|
33 |
+
protected handleRoleSpecificMessage(message: WebSocketMessage): void;
|
34 |
+
private handleFrameUpdate;
|
35 |
+
private handleVideoConfigUpdate;
|
36 |
+
private handleStreamStopped;
|
37 |
+
private handleRecoveryTriggered;
|
38 |
+
private handleStatusUpdate;
|
39 |
+
private handleStreamStats;
|
40 |
+
/**
|
41 |
+
* Create a consumer and automatically connect to a room
|
42 |
+
*/
|
43 |
+
static createAndConnect(workspaceId: string, roomId: string, baseUrl?: string, participantId?: string): Promise<VideoConsumer>;
|
44 |
+
/**
|
45 |
+
* Get the video element for displaying the remote stream
|
46 |
+
*/
|
47 |
+
attachToVideoElement(videoElement: HTMLVideoElement): void;
|
48 |
+
/**
|
49 |
+
* Get current video statistics
|
50 |
+
*/
|
51 |
+
getVideoStats(): Promise<WebRTCStats | null>;
|
52 |
+
}
|
client/js/dist/video/core.d.ts
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Core video client for LeRobot Arena
|
3 |
+
* Base class providing REST API, WebSocket, and WebRTC functionality
|
4 |
+
*/
|
5 |
+
import { EventEmitter } from 'eventemitter3';
|
6 |
+
import type { ParticipantRole, RoomInfo, RoomState, ConnectionInfo, WebSocketMessage, WebRTCSignalResponse, ClientOptions, WebRTCConfig, WebRTCStats, VideoConfig, RecoveryConfig, ErrorCallback, ConnectedCallback, DisconnectedCallback } from './types.js';
|
7 |
+
export declare class VideoClientCore extends EventEmitter {
|
8 |
+
protected baseUrl: string;
|
9 |
+
protected apiBase: string;
|
10 |
+
protected websocket: WebSocket | null;
|
11 |
+
protected peerConnection: RTCPeerConnection | null;
|
12 |
+
protected localStream: MediaStream | null;
|
13 |
+
protected remoteStream: MediaStream | null;
|
14 |
+
protected workspaceId: string | null;
|
15 |
+
protected roomId: string | null;
|
16 |
+
protected role: ParticipantRole | null;
|
17 |
+
protected participantId: string | null;
|
18 |
+
protected connected: boolean;
|
19 |
+
protected options: ClientOptions;
|
20 |
+
protected webrtcConfig: WebRTCConfig;
|
21 |
+
protected onErrorCallback: ErrorCallback | null;
|
22 |
+
protected onConnectedCallback: ConnectedCallback | null;
|
23 |
+
protected onDisconnectedCallback: DisconnectedCallback | null;
|
24 |
+
constructor(baseUrl?: string, options?: ClientOptions);
|
25 |
+
listRooms(workspaceId: string): Promise<RoomInfo[]>;
|
26 |
+
createRoom(workspaceId?: string, roomId?: string, config?: VideoConfig, recoveryConfig?: RecoveryConfig): Promise<{
|
27 |
+
workspaceId: string;
|
28 |
+
roomId: string;
|
29 |
+
}>;
|
30 |
+
deleteRoom(workspaceId: string, roomId: string): Promise<boolean>;
|
31 |
+
getRoomState(workspaceId: string, roomId: string): Promise<RoomState>;
|
32 |
+
getRoomInfo(workspaceId: string, roomId: string): Promise<RoomInfo>;
|
33 |
+
sendWebRTCSignal(workspaceId: string, roomId: string, clientId: string, message: RTCSessionDescriptionInit | RTCIceCandidateInit | Record<string, unknown>): Promise<WebRTCSignalResponse>;
|
34 |
+
connectToRoom(workspaceId: string, roomId: string, role: ParticipantRole, participantId?: string): Promise<boolean>;
|
35 |
+
disconnect(): Promise<void>;
|
36 |
+
createPeerConnection(): RTCPeerConnection;
|
37 |
+
createOffer(): Promise<RTCSessionDescriptionInit>;
|
38 |
+
createAnswer(offer: RTCSessionDescriptionInit): Promise<RTCSessionDescriptionInit>;
|
39 |
+
setRemoteDescription(description: RTCSessionDescriptionInit): Promise<void>;
|
40 |
+
addIceCandidate(candidate: RTCIceCandidateInit): Promise<void>;
|
41 |
+
startProducing(constraints?: MediaStreamConstraints): Promise<MediaStream>;
|
42 |
+
startScreenShare(): Promise<MediaStream>;
|
43 |
+
stopProducing(): void;
|
44 |
+
getLocalStream(): MediaStream | null;
|
45 |
+
getRemoteStream(): MediaStream | null;
|
46 |
+
getPeerConnection(): RTCPeerConnection | null;
|
47 |
+
getStats(): Promise<WebRTCStats | null>;
|
48 |
+
protected sendJoinMessage(): void;
|
49 |
+
protected handleMessage(message: WebSocketMessage): void;
|
50 |
+
protected handleRoleSpecificMessage(message: WebSocketMessage): void;
|
51 |
+
protected handleError(errorMessage: string): void;
|
52 |
+
sendHeartbeat(): Promise<void>;
|
53 |
+
isConnected(): boolean;
|
54 |
+
getConnectionInfo(): ConnectionInfo;
|
55 |
+
onError(callback: ErrorCallback): void;
|
56 |
+
onConnected(callback: ConnectedCallback): void;
|
57 |
+
onDisconnected(callback: DisconnectedCallback): void;
|
58 |
+
private fetchApi;
|
59 |
+
private extractVideoStats;
|
60 |
+
protected generateWorkspaceId(): string;
|
61 |
+
}
|
client/js/dist/video/factory.d.ts
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Factory functions for creating LeRobot Arena video clients
|
3 |
+
*/
|
4 |
+
import { VideoProducer } from './producer.js';
|
5 |
+
import { VideoConsumer } from './consumer.js';
|
6 |
+
import type { ParticipantRole, ClientOptions } from './types.js';
|
7 |
+
/**
|
8 |
+
* Factory function to create the appropriate client based on role
|
9 |
+
*/
|
10 |
+
export declare function createClient(role: ParticipantRole, baseUrl?: string, options?: ClientOptions): VideoProducer | VideoConsumer;
|
11 |
+
/**
|
12 |
+
* Create and connect a producer client
|
13 |
+
*/
|
14 |
+
export declare function createProducerClient(baseUrl?: string, workspaceId?: string, roomId?: string, participantId?: string, options?: ClientOptions): Promise<VideoProducer>;
|
15 |
+
/**
|
16 |
+
* Create and connect a consumer client
|
17 |
+
*/
|
18 |
+
export declare function createConsumerClient(workspaceId: string, roomId: string, baseUrl?: string, participantId?: string, options?: ClientOptions): Promise<VideoConsumer>;
|
client/js/dist/video/index.d.ts
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* LeRobot Arena Video Client - Main Module
|
3 |
+
*
|
4 |
+
* TypeScript/JavaScript client for video streaming and monitoring
|
5 |
+
*/
|
6 |
+
export { VideoClientCore } from './core.js';
|
7 |
+
export { VideoProducer } from './producer.js';
|
8 |
+
export { VideoConsumer } from './consumer.js';
|
9 |
+
export * from './types.js';
|
10 |
+
export { createProducerClient, createConsumerClient, createClient } from './factory.js';
|
client/js/dist/video/producer.d.ts
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Producer client for video streaming in LeRobot Arena
|
3 |
+
*/
|
4 |
+
import { VideoClientCore } from './core.js';
|
5 |
+
import type { WebSocketMessage, ClientOptions, VideoConfig } from './types.js';
|
6 |
+
export declare class VideoProducer extends VideoClientCore {
|
7 |
+
private consumerConnections;
|
8 |
+
constructor(baseUrl?: string, options?: ClientOptions);
|
9 |
+
connect(workspaceId: string, roomId: string, participantId?: string): Promise<boolean>;
|
10 |
+
private connectToExistingConsumers;
|
11 |
+
private createPeerConnectionForConsumer;
|
12 |
+
private restartConnectionToConsumer;
|
13 |
+
private handleConsumerLeft;
|
14 |
+
private restartConnectionsWithNewStream;
|
15 |
+
startCamera(constraints?: MediaStreamConstraints): Promise<MediaStream>;
|
16 |
+
startScreenShare(): Promise<MediaStream>;
|
17 |
+
stopStreaming(): Promise<void>;
|
18 |
+
updateVideoConfig(config: VideoConfig): Promise<void>;
|
19 |
+
sendEmergencyStop(reason?: string): Promise<void>;
|
20 |
+
initiateWebRTCWithConsumer(consumerId: string): Promise<void>;
|
21 |
+
private handleWebRTCAnswer;
|
22 |
+
private handleWebRTCIce;
|
23 |
+
protected handleRoleSpecificMessage(message: WebSocketMessage): void;
|
24 |
+
private handleStatusUpdate;
|
25 |
+
private handleStreamStats;
|
26 |
+
private notifyStreamStarted;
|
27 |
+
private notifyStreamStopped;
|
28 |
+
/**
|
29 |
+
* Create a room and automatically connect as producer
|
30 |
+
*/
|
31 |
+
static createAndConnect(baseUrl?: string, workspaceId?: string, roomId?: string, participantId?: string): Promise<VideoProducer>;
|
32 |
+
/**
|
33 |
+
* Get the current room ID (useful when auto-created)
|
34 |
+
*/
|
35 |
+
get currentRoomId(): string | null;
|
36 |
+
}
|
client/js/dist/video/types.d.ts
ADDED
@@ -0,0 +1,249 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Type definitions for LeRobot Arena Video Client
|
3 |
+
* ✅ Fully synchronized with server-side models.py
|
4 |
+
*/
|
5 |
+
export type ParticipantRole = 'producer' | 'consumer';
|
6 |
+
export type MessageType = 'frame_update' | 'video_config_update' | 'stream_started' | 'stream_stopped' | 'recovery_triggered' | 'heartbeat' | 'heartbeat_ack' | 'emergency_stop' | 'joined' | 'error' | 'participant_joined' | 'participant_left' | 'webrtc_offer' | 'webrtc_answer' | 'webrtc_ice' | 'status_update' | 'stream_stats';
|
7 |
+
export interface VideoConfig {
|
8 |
+
encoding?: VideoEncoding;
|
9 |
+
resolution?: Resolution;
|
10 |
+
framerate?: number;
|
11 |
+
bitrate?: number;
|
12 |
+
quality?: number;
|
13 |
+
}
|
14 |
+
export interface Resolution {
|
15 |
+
width: number;
|
16 |
+
height: number;
|
17 |
+
}
|
18 |
+
export type VideoEncoding = 'jpeg' | 'h264' | 'vp8' | 'vp9';
|
19 |
+
export type RecoveryPolicy = 'freeze_last_frame' | 'connection_info' | 'black_screen' | 'fade_to_black' | 'overlay_status';
|
20 |
+
export interface RecoveryConfig {
|
21 |
+
frame_timeout_ms?: number;
|
22 |
+
max_frame_reuse_count?: number;
|
23 |
+
recovery_policy?: RecoveryPolicy;
|
24 |
+
fallback_policy?: RecoveryPolicy;
|
25 |
+
show_hold_indicators?: boolean;
|
26 |
+
info_frame_bg_color?: [number, number, number];
|
27 |
+
info_frame_text_color?: [number, number, number];
|
28 |
+
fade_intensity?: number;
|
29 |
+
overlay_opacity?: number;
|
30 |
+
}
|
31 |
+
export interface FrameData {
|
32 |
+
data: ArrayBuffer;
|
33 |
+
metadata?: Record<string, unknown>;
|
34 |
+
}
|
35 |
+
export interface StreamStats {
|
36 |
+
stream_id: string;
|
37 |
+
duration_seconds: number;
|
38 |
+
frame_count: number;
|
39 |
+
total_bytes: number;
|
40 |
+
average_fps: number;
|
41 |
+
average_bitrate: number;
|
42 |
+
}
|
43 |
+
export interface ParticipantInfo {
|
44 |
+
producer: string | null;
|
45 |
+
consumers: string[];
|
46 |
+
total: number;
|
47 |
+
}
|
48 |
+
export interface RoomInfo {
|
49 |
+
id: string;
|
50 |
+
workspace_id: string;
|
51 |
+
participants: ParticipantInfo;
|
52 |
+
frame_count: number;
|
53 |
+
config: VideoConfig;
|
54 |
+
has_producer: boolean;
|
55 |
+
active_consumers: number;
|
56 |
+
}
|
57 |
+
export interface RoomState {
|
58 |
+
room_id: string;
|
59 |
+
workspace_id: string;
|
60 |
+
participants: ParticipantInfo;
|
61 |
+
frame_count: number;
|
62 |
+
last_frame_time: string | null;
|
63 |
+
current_config: VideoConfig;
|
64 |
+
timestamp: string;
|
65 |
+
}
|
66 |
+
export interface ConnectionInfo {
|
67 |
+
connected: boolean;
|
68 |
+
workspace_id: string | null;
|
69 |
+
room_id: string | null;
|
70 |
+
role: ParticipantRole | null;
|
71 |
+
participant_id: string | null;
|
72 |
+
base_url: string;
|
73 |
+
}
|
74 |
+
export interface BaseMessage {
|
75 |
+
type: MessageType;
|
76 |
+
timestamp?: string;
|
77 |
+
}
|
78 |
+
export interface FrameUpdateMessage extends BaseMessage {
|
79 |
+
type: 'frame_update';
|
80 |
+
data: ArrayBuffer;
|
81 |
+
metadata?: Record<string, unknown>;
|
82 |
+
}
|
83 |
+
export interface VideoConfigUpdateMessage extends BaseMessage {
|
84 |
+
type: 'video_config_update';
|
85 |
+
config: VideoConfig;
|
86 |
+
source?: string;
|
87 |
+
}
|
88 |
+
export interface StreamStartedMessage extends BaseMessage {
|
89 |
+
type: 'stream_started';
|
90 |
+
config: VideoConfig;
|
91 |
+
participant_id: string;
|
92 |
+
}
|
93 |
+
export interface StreamStoppedMessage extends BaseMessage {
|
94 |
+
type: 'stream_stopped';
|
95 |
+
participant_id: string;
|
96 |
+
reason?: string;
|
97 |
+
}
|
98 |
+
export interface RecoveryTriggeredMessage extends BaseMessage {
|
99 |
+
type: 'recovery_triggered';
|
100 |
+
policy: RecoveryPolicy;
|
101 |
+
reason: string;
|
102 |
+
}
|
103 |
+
export interface HeartbeatMessage extends BaseMessage {
|
104 |
+
type: 'heartbeat';
|
105 |
+
}
|
106 |
+
export interface HeartbeatAckMessage extends BaseMessage {
|
107 |
+
type: 'heartbeat_ack';
|
108 |
+
}
|
109 |
+
export interface EmergencyStopMessage extends BaseMessage {
|
110 |
+
type: 'emergency_stop';
|
111 |
+
reason: string;
|
112 |
+
source?: string;
|
113 |
+
}
|
114 |
+
export interface JoinedMessage extends BaseMessage {
|
115 |
+
type: 'joined';
|
116 |
+
room_id: string;
|
117 |
+
role: ParticipantRole;
|
118 |
+
}
|
119 |
+
export interface ErrorMessage extends BaseMessage {
|
120 |
+
type: 'error';
|
121 |
+
message: string;
|
122 |
+
code?: string;
|
123 |
+
}
|
124 |
+
export interface ParticipantJoinedMessage extends BaseMessage {
|
125 |
+
type: 'participant_joined';
|
126 |
+
room_id: string;
|
127 |
+
participant_id: string;
|
128 |
+
role: ParticipantRole;
|
129 |
+
}
|
130 |
+
export interface ParticipantLeftMessage extends BaseMessage {
|
131 |
+
type: 'participant_left';
|
132 |
+
room_id: string;
|
133 |
+
participant_id: string;
|
134 |
+
role: ParticipantRole;
|
135 |
+
}
|
136 |
+
export interface WebRTCOfferMessage extends BaseMessage {
|
137 |
+
type: 'webrtc_offer';
|
138 |
+
offer: RTCSessionDescriptionInit;
|
139 |
+
from_producer: string;
|
140 |
+
}
|
141 |
+
export interface WebRTCAnswerMessage extends BaseMessage {
|
142 |
+
type: 'webrtc_answer';
|
143 |
+
answer: RTCSessionDescriptionInit;
|
144 |
+
from_consumer: string;
|
145 |
+
}
|
146 |
+
export interface WebRTCIceMessage extends BaseMessage {
|
147 |
+
type: 'webrtc_ice';
|
148 |
+
candidate: RTCIceCandidateInit;
|
149 |
+
from_producer?: string;
|
150 |
+
from_consumer?: string;
|
151 |
+
}
|
152 |
+
export interface StatusUpdateMessage extends BaseMessage {
|
153 |
+
type: 'status_update';
|
154 |
+
status: string;
|
155 |
+
data?: Record<string, unknown>;
|
156 |
+
}
|
157 |
+
export interface StreamStatsMessage extends BaseMessage {
|
158 |
+
type: 'stream_stats';
|
159 |
+
stats: StreamStats;
|
160 |
+
}
|
161 |
+
export type WebSocketMessage = FrameUpdateMessage | VideoConfigUpdateMessage | StreamStartedMessage | StreamStoppedMessage | RecoveryTriggeredMessage | HeartbeatMessage | HeartbeatAckMessage | EmergencyStopMessage | JoinedMessage | ErrorMessage | ParticipantJoinedMessage | ParticipantLeftMessage | WebRTCOfferMessage | WebRTCAnswerMessage | WebRTCIceMessage | StatusUpdateMessage | StreamStatsMessage;
|
162 |
+
export interface ApiResponse<T = unknown> {
|
163 |
+
success: boolean;
|
164 |
+
data?: T;
|
165 |
+
error?: string;
|
166 |
+
message?: string;
|
167 |
+
}
|
168 |
+
export interface ListRoomsResponse {
|
169 |
+
success: boolean;
|
170 |
+
workspace_id: string;
|
171 |
+
rooms: RoomInfo[];
|
172 |
+
total: number;
|
173 |
+
}
|
174 |
+
export interface CreateRoomResponse {
|
175 |
+
success: boolean;
|
176 |
+
workspace_id: string;
|
177 |
+
room_id: string;
|
178 |
+
message: string;
|
179 |
+
}
|
180 |
+
export interface GetRoomResponse {
|
181 |
+
success: boolean;
|
182 |
+
workspace_id: string;
|
183 |
+
room: RoomInfo;
|
184 |
+
}
|
185 |
+
export interface GetRoomStateResponse {
|
186 |
+
success: boolean;
|
187 |
+
workspace_id: string;
|
188 |
+
state: RoomState;
|
189 |
+
}
|
190 |
+
export interface DeleteRoomResponse {
|
191 |
+
success: boolean;
|
192 |
+
workspace_id: string;
|
193 |
+
message: string;
|
194 |
+
}
|
195 |
+
export interface WebRTCSignalResponse {
|
196 |
+
success: boolean;
|
197 |
+
workspace_id: string;
|
198 |
+
response?: RTCSessionDescriptionInit | RTCIceCandidateInit;
|
199 |
+
message?: string;
|
200 |
+
}
|
201 |
+
export interface CreateRoomRequest {
|
202 |
+
room_id?: string;
|
203 |
+
workspace_id?: string;
|
204 |
+
name?: string;
|
205 |
+
config?: VideoConfig;
|
206 |
+
recovery_config?: RecoveryConfig;
|
207 |
+
max_consumers?: number;
|
208 |
+
}
|
209 |
+
export interface WebRTCSignalRequest {
|
210 |
+
client_id: string;
|
211 |
+
message: RTCSessionDescriptionInit | RTCIceCandidateInit | Record<string, unknown>;
|
212 |
+
}
|
213 |
+
export interface JoinMessage {
|
214 |
+
participant_id: string;
|
215 |
+
role: ParticipantRole;
|
216 |
+
}
|
217 |
+
export interface WebRTCConfig {
|
218 |
+
iceServers?: RTCIceServer[];
|
219 |
+
constraints?: MediaStreamConstraints;
|
220 |
+
bitrate?: number;
|
221 |
+
framerate?: number;
|
222 |
+
resolution?: Resolution;
|
223 |
+
codecPreferences?: string[];
|
224 |
+
}
|
225 |
+
export interface WebRTCStats {
|
226 |
+
videoBitsPerSecond: number;
|
227 |
+
framesPerSecond: number;
|
228 |
+
frameWidth: number;
|
229 |
+
frameHeight: number;
|
230 |
+
packetsLost: number;
|
231 |
+
totalPackets: number;
|
232 |
+
}
|
233 |
+
export type FrameUpdateCallback = (frame: FrameData) => void;
|
234 |
+
export type VideoConfigUpdateCallback = (config: VideoConfig) => void;
|
235 |
+
export type StreamStartedCallback = (config: VideoConfig, participantId: string) => void;
|
236 |
+
export type StreamStoppedCallback = (participantId: string, reason?: string) => void;
|
237 |
+
export type RecoveryTriggeredCallback = (policy: RecoveryPolicy, reason: string) => void;
|
238 |
+
export type StatusUpdateCallback = (status: string, data?: Record<string, unknown>) => void;
|
239 |
+
export type StreamStatsCallback = (stats: StreamStats) => void;
|
240 |
+
export type ErrorCallback = (error: string) => void;
|
241 |
+
export type ConnectedCallback = () => void;
|
242 |
+
export type DisconnectedCallback = () => void;
|
243 |
+
export interface ClientOptions {
|
244 |
+
base_url?: string;
|
245 |
+
timeout?: number;
|
246 |
+
reconnect_attempts?: number;
|
247 |
+
heartbeat_interval?: number;
|
248 |
+
webrtc_config?: WebRTCConfig;
|
249 |
+
}
|
client/js/tsconfig.json
CHANGED
@@ -6,7 +6,6 @@
|
|
6 |
"moduleResolution": "bundler",
|
7 |
"allowImportingTsExtensions": true,
|
8 |
"verbatimModuleSyntax": true,
|
9 |
-
"noEmit": true,
|
10 |
"declaration": true,
|
11 |
"emitDeclarationOnly": true,
|
12 |
"outDir": "dist",
|
|
|
6 |
"moduleResolution": "bundler",
|
7 |
"allowImportingTsExtensions": true,
|
8 |
"verbatimModuleSyntax": true,
|
|
|
9 |
"declaration": true,
|
10 |
"emitDeclarationOnly": true,
|
11 |
"outDir": "dist",
|