@kaltura-sdk/rtc-avatar 1.32.0

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/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@kaltura-sdk/rtc-avatar",
3
+ "version": "1.32.0",
4
+ "author": "kaltura",
5
+ "license": "AGPL-3.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/kaltura/rtc"
9
+ },
10
+ "types": "./src/index.d.ts",
11
+ "dependencies": {
12
+ "@kaltura-sdk/rtc-core": "^1.25.0",
13
+ "@unisphere/core": "^1.91.1",
14
+ "lodash.isequal": "^4.5.0"
15
+ },
16
+ "module": "./index.esm.js",
17
+ "type": "module",
18
+ "publishConfig": {
19
+ "registry": "https://registry.npmjs.org"
20
+ }
21
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './lib/eself-demo';
2
+ export * from './lib/session';
3
+ export * from './lib/dom';
4
+ export * from './lib/signaling';
5
+ export * from './lib/connection';
6
+ export * from './lib/utils/logsCollector';
@@ -0,0 +1,186 @@
1
+ import { PeerConnection, PeerConnectionConfig, IceConfiguration, CoreRTCSession, TrackKind, GetUserMediaEveObj, VideoSenderConfig } from '@kaltura-sdk/rtc-core';
2
+ import { EselfSignaling } from '../signaling';
3
+ import { ConnectionType, ConnectionEvent, ConnectionEventPayloads, ConnectionState, MediaTrackState } from './types';
4
+ import { IceCandidateData } from '../session';
5
+ /**
6
+ * Options for configuring the RTC connection behavior.
7
+ */
8
+ export interface EselfRTCConnectionOptions {
9
+ /** Force video codec (e.g. 'H264', 'VP8') */
10
+ videoCodec?: string;
11
+ /** Force audio codec (e.g. 'opus') */
12
+ audioCodec?: string;
13
+ /** Enable trickle ICE for this connection */
14
+ enableTrickleIce?: boolean;
15
+ /** Degradation preference for the video sender */
16
+ videoDegradationPreference?: RTCDegradationPreference;
17
+ /** Content hint for the video track */
18
+ videoContentHint?: string;
19
+ /** Maximum frame rate for the video sender */
20
+ videoMaxFps?: number;
21
+ /** Maximum bitrate in Kilobits for the video sender */
22
+ videoMaxBitrateKbps?: number;
23
+ /** Scale resolution down factor for the video sender (1.0 = no scaling) */
24
+ videoScaleResolutionDownBy?: number;
25
+ }
26
+ /**
27
+ * Event listener type for connection events
28
+ */
29
+ type EventListener<T extends ConnectionEvent> = (payload: ConnectionEventPayloads[T]) => void;
30
+ /**
31
+ * EselfRTCConnection: Per-connection coordinator that wraps ONE core SDK PeerConnection
32
+ *
33
+ * Purpose:
34
+ * - Wraps a single PeerConnection from the core SDK
35
+ * - Handles signaling for this connection
36
+ * - Emits simplified events to EselfSession
37
+ * - Manages connection lifecycle (NO retry logic in Phase 2a)
38
+ *
39
+ * Two modes:
40
+ * - Publisher: Sends local stream (e.g., ASR audio publishing)
41
+ * - Viewer: Receives remote stream only (e.g., STV avatar viewing)
42
+ *
43
+ * Events emitted:
44
+ * - pcConnected: Connection established
45
+ * - pcConnectionFailed: Connection failed
46
+ * - pcTrackReceived: Remote track received
47
+ * - pcIceCandidate: Local ICE candidate generated
48
+ */
49
+ export declare class EselfRTCConnection {
50
+ private connectionId;
51
+ private connectionType;
52
+ private peerConnection;
53
+ private signalingClient;
54
+ private logger;
55
+ private state;
56
+ private localStream;
57
+ private videoElementId;
58
+ private options;
59
+ useRelay: boolean;
60
+ private audioState;
61
+ private videoState;
62
+ private isReconnecting;
63
+ private requestsDebouncer;
64
+ private hwMuteDebounceTimer;
65
+ private readonly HW_MUTE_DEBOUNCE_MS;
66
+ private coreRTCSession;
67
+ private getUserMediaCallback;
68
+ private eventListeners;
69
+ constructor(connectionId: string, connectionType: ConnectionType, signalingClient: EselfSignaling, createPeerConnection: (connectionId: string, config: PeerConnectionConfig, callbacks: any) => PeerConnection, coreRTCSession: CoreRTCSession, getUserMediaCallback: (audio: boolean, video: boolean, elementId?: string, isDeviceChange?: boolean) => Promise<{
70
+ gumResult: GetUserMediaEveObj;
71
+ stream: MediaStream | null;
72
+ }>, options?: EselfRTCConnectionOptions);
73
+ /**
74
+ * Sets the video element ID for DOM reattachment during unmute
75
+ * @param elementId - The container element ID where video should be attached
76
+ */
77
+ setVideoElementId(elementId: string | null): void;
78
+ /**
79
+ * Sets the reconnection flag
80
+ * @param value - True if this is a reconnection attempt
81
+ */
82
+ setReconnecting(value: boolean): void;
83
+ /**
84
+ * Test method to manually trigger connection failed event
85
+ * Used for testing reconnection logic in development/testing
86
+ */
87
+ testTriggerConnectionFailed(): void;
88
+ /**
89
+ * Create and configure the peer connection
90
+ *
91
+ * @param iceConfig - ICE server configuration
92
+ * @param localStream - Optional local stream for publisher connections
93
+ * @param videoElementId - Optional element ID for video attachment
94
+ * @throws Error if connection creation fails
95
+ */
96
+ createConnection(iceConfig: IceConfiguration, localStream?: MediaStream, videoElementId?: string): Promise<void>;
97
+ /**
98
+ * Handle a remote offer (for viewer mode)
99
+ * Creates answer and sends it via signaling
100
+ *
101
+ * @param sdp - Remote SDP offer
102
+ */
103
+ handleRemoteOffer(sdp: RTCSessionDescriptionInit): Promise<void>;
104
+ /**
105
+ * Handle a remote answer (after sending offer)
106
+ *
107
+ * @param sdp - Remote SDP answer
108
+ */
109
+ handleRemoteAnswer(sdp: RTCSessionDescriptionInit, videoSenderConfig?: VideoSenderConfig | null): Promise<void>;
110
+ /**
111
+ * Handle a remote ICE candidate
112
+ *
113
+ * @param candidate - Remote ICE candidate
114
+ */
115
+ handleRemoteICECandidate(candidate: IceCandidateData): Promise<void>;
116
+ /**
117
+ * Register an event listener
118
+ *
119
+ * @param event - Event type
120
+ * @param listener - Listener function
121
+ */
122
+ on<T extends ConnectionEvent>(event: T, listener: EventListener<T>): void;
123
+ /**
124
+ * Remove an event listener
125
+ *
126
+ * @param event - Event type
127
+ * @param listener - Listener function
128
+ */
129
+ off<T extends ConnectionEvent>(event: T, listener: EventListener<T>): void;
130
+ /**
131
+ * Close the connection and clean up resources
132
+ */
133
+ close(): void;
134
+ /**
135
+ * Get current connection state
136
+ */
137
+ getState(): ConnectionState;
138
+ /**
139
+ * Get the underlying core SDK PeerConnection (for advanced use)
140
+ */
141
+ getPeerConnection(): PeerConnection | null;
142
+ private handlePcCreated;
143
+ private handlePcConnected;
144
+ private handlePcConnectedFinal;
145
+ private handlePcConnectionFail;
146
+ private handlePcTrackEvent;
147
+ private handleStartPublishing;
148
+ private handleIceCandidate;
149
+ /**
150
+ * Generic method to mute a track using RequestsDebouncer with state comparison
151
+ * Protects against rapid duplicate calls from the app
152
+ * @param trackKind - TrackKind.AUDIO or TrackKind.VIDEO
153
+ */
154
+ muteTrack(trackKind: TrackKind): Promise<void>;
155
+ /**
156
+ * Generic method to unmute a track using RequestsDebouncer with state comparison
157
+ * Calls getUserMedia through callback to preserve constraints
158
+ * @param trackKind - TrackKind.AUDIO or TrackKind.VIDEO
159
+ */
160
+ unmuteTrack(trackKind: TrackKind): Promise<boolean>;
161
+ muteAudio(): Promise<void>;
162
+ unmuteAudio(): Promise<boolean>;
163
+ muteVideo(): Promise<void>;
164
+ unmuteVideo(): Promise<boolean>;
165
+ /**
166
+ * Sets up hardware mute detection on tracks
167
+ * Should be called after tracks are added to connection
168
+ */
169
+ setupHardwareMuteDetection(): void;
170
+ /**
171
+ * Handles track mute event (hardware mute detected)
172
+ * Uses 5-second debounce to avoid false positives
173
+ */
174
+ private handleTrackMute;
175
+ /**
176
+ * Handles track unmute event (hardware unmute detected)
177
+ */
178
+ private handleTrackUnmute;
179
+ getAudioState(): MediaTrackState;
180
+ getVideoState(): MediaTrackState;
181
+ /**
182
+ * Emit an event to all registered listeners
183
+ */
184
+ private emit;
185
+ }
186
+ export default EselfRTCConnection;
@@ -0,0 +1,3 @@
1
+ export { EselfRTCConnection, default as EselfRTCConnectionDefault, } from './EselfRTCConnection';
2
+ export type { EselfRTCConnectionOptions } from './EselfRTCConnection';
3
+ export * from './types';
@@ -0,0 +1,94 @@
1
+ import { IceCandidateData } from '../session';
2
+ /**
3
+ * Connection type for EselfRTCConnection
4
+ */
5
+ export type ConnectionType = 'publisher' | 'viewer';
6
+ /**
7
+ * Media track mute state
8
+ */
9
+ export declare enum MediaTrackState {
10
+ UNMUTED = "UNMUTED",// Track active, not muted
11
+ MUTED = "MUTED",// Software muted by user
12
+ HW_MUTED = "HW_MUTED"
13
+ }
14
+ /**
15
+ * ICE configuration for peer connections
16
+ */
17
+ export type IceConfiguration = {
18
+ iceServers: RTCIceServer[];
19
+ iceTransportPolicy?: RTCIceTransportPolicy;
20
+ bundlePolicy?: RTCBundlePolicy;
21
+ rtcpMuxPolicy?: RTCRtcpMuxPolicy;
22
+ };
23
+ /**
24
+ * Events emitted by EselfRTCConnection
25
+ */
26
+ export declare enum ConnectionEvent {
27
+ PC_CONNECTED = "pcConnected",
28
+ PC_CONNECTION_FAILED = "pcConnectionFailed",
29
+ PC_TRACK_RECEIVED = "pcTrackReceived",
30
+ PC_ICE_CANDIDATE = "pcIceCandidate",
31
+ AUDIO_MUTED = "audio-muted",
32
+ AUDIO_UNMUTED = "audio-unmuted",
33
+ VIDEO_MUTED = "video-muted",
34
+ VIDEO_UNMUTED = "video-unmuted",
35
+ HW_AUDIO_MUTED = "hw-audio-muted",
36
+ HW_AUDIO_UNMUTED = "hw-audio-unmuted"
37
+ }
38
+ /**
39
+ * Connection event payloads
40
+ */
41
+ export type ConnectionEventPayloads = {
42
+ [ConnectionEvent.PC_CONNECTED]: {
43
+ connectionId: string;
44
+ };
45
+ [ConnectionEvent.PC_CONNECTION_FAILED]: {
46
+ connectionId: string;
47
+ error: Error;
48
+ };
49
+ [ConnectionEvent.PC_TRACK_RECEIVED]: {
50
+ connectionId: string;
51
+ stream: MediaStream;
52
+ track: MediaStreamTrack;
53
+ };
54
+ [ConnectionEvent.PC_ICE_CANDIDATE]: {
55
+ connectionId: string;
56
+ iceCandidate: IceCandidateData | null;
57
+ };
58
+ [ConnectionEvent.AUDIO_MUTED]: {
59
+ connectionId: string;
60
+ state: MediaTrackState;
61
+ };
62
+ [ConnectionEvent.AUDIO_UNMUTED]: {
63
+ connectionId: string;
64
+ state: MediaTrackState;
65
+ };
66
+ [ConnectionEvent.VIDEO_MUTED]: {
67
+ connectionId: string;
68
+ state: MediaTrackState;
69
+ };
70
+ [ConnectionEvent.VIDEO_UNMUTED]: {
71
+ connectionId: string;
72
+ state: MediaTrackState;
73
+ };
74
+ [ConnectionEvent.HW_AUDIO_MUTED]: {
75
+ connectionId: string;
76
+ previousState: MediaTrackState;
77
+ currentState: MediaTrackState;
78
+ };
79
+ [ConnectionEvent.HW_AUDIO_UNMUTED]: {
80
+ connectionId: string;
81
+ currentState: MediaTrackState;
82
+ message: string;
83
+ };
84
+ };
85
+ /**
86
+ * Connection state
87
+ */
88
+ export declare enum ConnectionState {
89
+ IDLE = "idle",
90
+ CONNECTING = "connecting",
91
+ CONNECTED = "connected",
92
+ FAILED = "failed",
93
+ CLOSED = "closed"
94
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * EselfDOMManager: Handles DOM manipulation and tracks multiple attachments per stream
3
+ *
4
+ * Key Features:
5
+ * - One stream can be attached to multiple video containers
6
+ * - Audio streams are attached to the body (one audio element per stream)
7
+ * - Tracks all attachments for proper cleanup
8
+ * - Gracefully handles missing containers (logs warning, doesn't throw)
9
+ */
10
+ export declare class EselfDOMManager {
11
+ private logger;
12
+ private streamAttachments;
13
+ private audioElements;
14
+ constructor();
15
+ /**
16
+ * Attach a video stream to a container element
17
+ * Creates a video element inside the container and plays the stream
18
+ * Same stream can be attached to multiple containers
19
+ *
20
+ * @param stream - MediaStream to attach
21
+ * @param containerElementId - ID of the container element
22
+ */
23
+ attachVideoStream(stream: MediaStream, containerElementId: string): void;
24
+ /**
25
+ * Attach an audio stream to the document body
26
+ * Creates an audio element in the body (not in a container)
27
+ * One audio element per stream (not multiple like video)
28
+ *
29
+ * @param stream - MediaStream to attach
30
+ */
31
+ attachAudioStream(stream: MediaStream): void;
32
+ /**
33
+ * Detach a stream from a specific container element
34
+ * Removes the video element from that container only
35
+ * Stream may still be attached to other containers
36
+ *
37
+ * @param streamId - ID of the stream
38
+ * @param containerElementId - ID of the container to detach from
39
+ */
40
+ detachStreamFromElement(streamId: string, containerElementId: string): void;
41
+ /**
42
+ * Detach a stream from ALL elements (all video containers + audio)
43
+ * Removes all video elements and audio element for this stream
44
+ *
45
+ * @param streamId - ID of the stream to fully detach
46
+ */
47
+ detachStream(streamId: string): void;
48
+ /**
49
+ * Clean up all tracked streams and elements
50
+ * Detaches all video and audio elements
51
+ * Call this on session destroy
52
+ */
53
+ cleanup(): void;
54
+ /**
55
+ * Check if a stream is attached to any elements
56
+ * @param streamId - ID of the stream to check
57
+ * @returns true if stream has any attachments (video or audio)
58
+ */
59
+ isStreamAttached(streamId: string): boolean;
60
+ /**
61
+ * Get all container IDs that a stream is attached to
62
+ * @param streamId - ID of the stream
63
+ * @returns Array of container element IDs
64
+ */
65
+ getStreamAttachments(streamId: string): string[];
66
+ /**
67
+ * Update tracks in DOM elements for local media preview
68
+ * Used when device changes to replace old tracks with new tracks
69
+ * This is for local media only (getUserMedia streams), not remote streams
70
+ *
71
+ * @param newTrack - New track to replace in DOM elements
72
+ * @param streamElementMappings - Map of element tracking from EselfSession
73
+ */
74
+ updateLocalMediaTracks(newTrack: MediaStreamTrack, streamElementMappings: Map<string, {
75
+ audioElement: HTMLAudioElement | null;
76
+ videoElement: HTMLVideoElement | null;
77
+ videoContainerId: string | null;
78
+ }>): void;
79
+ }
80
+ export default EselfDOMManager;
@@ -0,0 +1 @@
1
+ export { EselfDOMManager, default as EselfDOMManagerDefault, } from './EselfDOMManager';
@@ -0,0 +1 @@
1
+ export declare const HiFromEsSelf: () => void;