@agatx/serenada-core 0.6.10

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.
Files changed (156) hide show
  1. package/dist/ConsoleLogger.d.ts +6 -0
  2. package/dist/ConsoleLogger.d.ts.map +1 -0
  3. package/dist/ConsoleLogger.js +21 -0
  4. package/dist/ConsoleLogger.js.map +1 -0
  5. package/dist/RoomWatcher.d.ts +34 -0
  6. package/dist/RoomWatcher.d.ts.map +1 -0
  7. package/dist/RoomWatcher.js +103 -0
  8. package/dist/RoomWatcher.js.map +1 -0
  9. package/dist/SerenadaCore.d.ts +47 -0
  10. package/dist/SerenadaCore.d.ts.map +1 -0
  11. package/dist/SerenadaCore.js +141 -0
  12. package/dist/SerenadaCore.js.map +1 -0
  13. package/dist/SerenadaDiagnostics.d.ts +49 -0
  14. package/dist/SerenadaDiagnostics.d.ts.map +1 -0
  15. package/dist/SerenadaDiagnostics.js +421 -0
  16. package/dist/SerenadaDiagnostics.js.map +1 -0
  17. package/dist/SerenadaServerProvider.d.ts +48 -0
  18. package/dist/SerenadaServerProvider.d.ts.map +1 -0
  19. package/dist/SerenadaServerProvider.js +296 -0
  20. package/dist/SerenadaServerProvider.js.map +1 -0
  21. package/dist/SerenadaSession.d.ts +180 -0
  22. package/dist/SerenadaSession.d.ts.map +1 -0
  23. package/dist/SerenadaSession.js +1082 -0
  24. package/dist/SerenadaSession.js.map +1 -0
  25. package/dist/SignalingProvider.d.ts +132 -0
  26. package/dist/SignalingProvider.d.ts.map +1 -0
  27. package/dist/SignalingProvider.js +50 -0
  28. package/dist/SignalingProvider.js.map +1 -0
  29. package/dist/api/roomApi.d.ts +2 -0
  30. package/dist/api/roomApi.d.ts.map +1 -0
  31. package/dist/api/roomApi.js +14 -0
  32. package/dist/api/roomApi.js.map +1 -0
  33. package/dist/cameraModes.d.ts +13 -0
  34. package/dist/cameraModes.d.ts.map +1 -0
  35. package/dist/cameraModes.js +35 -0
  36. package/dist/cameraModes.js.map +1 -0
  37. package/dist/configValidation.d.ts +10 -0
  38. package/dist/configValidation.d.ts.map +1 -0
  39. package/dist/configValidation.js +24 -0
  40. package/dist/configValidation.js.map +1 -0
  41. package/dist/constants.d.ts +33 -0
  42. package/dist/constants.d.ts.map +1 -0
  43. package/dist/constants.js +65 -0
  44. package/dist/constants.js.map +1 -0
  45. package/dist/formatError.d.ts +3 -0
  46. package/dist/formatError.d.ts.map +1 -0
  47. package/dist/formatError.js +7 -0
  48. package/dist/formatError.js.map +1 -0
  49. package/dist/iceServers.d.ts +2 -0
  50. package/dist/iceServers.d.ts.map +1 -0
  51. package/dist/iceServers.js +21 -0
  52. package/dist/iceServers.js.map +1 -0
  53. package/dist/index.d.ts +55 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +44 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/layout/computeLayout.d.ts +81 -0
  58. package/dist/layout/computeLayout.d.ts.map +1 -0
  59. package/dist/layout/computeLayout.js +380 -0
  60. package/dist/layout/computeLayout.js.map +1 -0
  61. package/dist/media/AudioLevelMonitor.d.ts +51 -0
  62. package/dist/media/AudioLevelMonitor.d.ts.map +1 -0
  63. package/dist/media/AudioLevelMonitor.js +179 -0
  64. package/dist/media/AudioLevelMonitor.js.map +1 -0
  65. package/dist/media/MediaEngine.d.ts +137 -0
  66. package/dist/media/MediaEngine.d.ts.map +1 -0
  67. package/dist/media/MediaEngine.js +1224 -0
  68. package/dist/media/MediaEngine.js.map +1 -0
  69. package/dist/media/callStats.d.ts +16 -0
  70. package/dist/media/callStats.d.ts.map +1 -0
  71. package/dist/media/callStats.js +214 -0
  72. package/dist/media/callStats.js.map +1 -0
  73. package/dist/media/localVideoRecovery.d.ts +16 -0
  74. package/dist/media/localVideoRecovery.d.ts.map +1 -0
  75. package/dist/media/localVideoRecovery.js +14 -0
  76. package/dist/media/localVideoRecovery.js.map +1 -0
  77. package/dist/recoveryStorage.d.ts +33 -0
  78. package/dist/recoveryStorage.d.ts.map +1 -0
  79. package/dist/recoveryStorage.js +88 -0
  80. package/dist/recoveryStorage.js.map +1 -0
  81. package/dist/serverUrls.d.ts +8 -0
  82. package/dist/serverUrls.d.ts.map +1 -0
  83. package/dist/serverUrls.js +65 -0
  84. package/dist/serverUrls.js.map +1 -0
  85. package/dist/signaling/SignalingEngine.d.ts +126 -0
  86. package/dist/signaling/SignalingEngine.d.ts.map +1 -0
  87. package/dist/signaling/SignalingEngine.js +720 -0
  88. package/dist/signaling/SignalingEngine.js.map +1 -0
  89. package/dist/signaling/payloads.d.ts +76 -0
  90. package/dist/signaling/payloads.d.ts.map +1 -0
  91. package/dist/signaling/payloads.js +160 -0
  92. package/dist/signaling/payloads.js.map +1 -0
  93. package/dist/signaling/roomStatuses.d.ts +9 -0
  94. package/dist/signaling/roomStatuses.d.ts.map +1 -0
  95. package/dist/signaling/roomStatuses.js +71 -0
  96. package/dist/signaling/roomStatuses.js.map +1 -0
  97. package/dist/signaling/transportConfig.d.ts +3 -0
  98. package/dist/signaling/transportConfig.d.ts.map +1 -0
  99. package/dist/signaling/transportConfig.js +27 -0
  100. package/dist/signaling/transportConfig.js.map +1 -0
  101. package/dist/signaling/transports/index.d.ts +13 -0
  102. package/dist/signaling/transports/index.d.ts.map +1 -0
  103. package/dist/signaling/transports/index.js +11 -0
  104. package/dist/signaling/transports/index.js.map +1 -0
  105. package/dist/signaling/transports/sse.d.ts +26 -0
  106. package/dist/signaling/transports/sse.d.ts.map +1 -0
  107. package/dist/signaling/transports/sse.js +131 -0
  108. package/dist/signaling/transports/sse.js.map +1 -0
  109. package/dist/signaling/transports/types.d.ts +17 -0
  110. package/dist/signaling/transports/types.d.ts.map +1 -0
  111. package/dist/signaling/transports/types.js +2 -0
  112. package/dist/signaling/transports/types.js.map +1 -0
  113. package/dist/signaling/transports/ws.d.ts +21 -0
  114. package/dist/signaling/transports/ws.d.ts.map +1 -0
  115. package/dist/signaling/transports/ws.js +93 -0
  116. package/dist/signaling/transports/ws.js.map +1 -0
  117. package/dist/signaling/types.d.ts +53 -0
  118. package/dist/signaling/types.d.ts.map +1 -0
  119. package/dist/signaling/types.js +2 -0
  120. package/dist/signaling/types.js.map +1 -0
  121. package/dist/types.d.ts +279 -0
  122. package/dist/types.d.ts.map +1 -0
  123. package/dist/types.js +3 -0
  124. package/dist/types.js.map +1 -0
  125. package/package.json +43 -0
  126. package/src/ConsoleLogger.ts +14 -0
  127. package/src/RoomWatcher.ts +127 -0
  128. package/src/SerenadaCore.ts +163 -0
  129. package/src/SerenadaDiagnostics.ts +485 -0
  130. package/src/SerenadaServerProvider.ts +362 -0
  131. package/src/SerenadaSession.ts +1258 -0
  132. package/src/SignalingProvider.ts +207 -0
  133. package/src/api/roomApi.ts +16 -0
  134. package/src/cameraModes.ts +34 -0
  135. package/src/configValidation.ts +35 -0
  136. package/src/constants.ts +77 -0
  137. package/src/formatError.ts +5 -0
  138. package/src/iceServers.ts +20 -0
  139. package/src/index.ts +155 -0
  140. package/src/layout/computeLayout.ts +639 -0
  141. package/src/media/AudioLevelMonitor.ts +190 -0
  142. package/src/media/MediaEngine.ts +1183 -0
  143. package/src/media/callStats.ts +260 -0
  144. package/src/media/localVideoRecovery.ts +39 -0
  145. package/src/recoveryStorage.ts +101 -0
  146. package/src/serverUrls.ts +69 -0
  147. package/src/signaling/SignalingEngine.ts +762 -0
  148. package/src/signaling/payloads.ts +215 -0
  149. package/src/signaling/roomStatuses.ts +89 -0
  150. package/src/signaling/transportConfig.ts +30 -0
  151. package/src/signaling/transports/index.ts +26 -0
  152. package/src/signaling/transports/sse.ts +146 -0
  153. package/src/signaling/transports/types.ts +19 -0
  154. package/src/signaling/transports/ws.ts +108 -0
  155. package/src/signaling/types.ts +68 -0
  156. package/src/types.ts +299 -0
@@ -0,0 +1,51 @@
1
+ import type { SerenadaLogger } from '../types.js';
2
+ export interface AudioLevelMonitorOptions {
3
+ /** AnalyserNode smoothingTimeConstant (0..1). Defaults to 0.5. */
4
+ smoothing?: number;
5
+ /** AnalyserNode FFT size — power of two. Defaults to 1024. */
6
+ fftSize?: number;
7
+ /** Subscriber notification interval in ms. Defaults to 100. */
8
+ updateIntervalMs?: number;
9
+ /** Reuse an existing AudioContext (the monitor will not close it on dispose). */
10
+ audioContext?: AudioContext;
11
+ /** Optional logger for diagnostics. */
12
+ logger?: SerenadaLogger;
13
+ }
14
+ type LevelCallback = (level: number) => void;
15
+ /**
16
+ * Computes a normalized speech audio level (0..1) from a MediaStream's audio
17
+ * track using the Web Audio API. Use it to drive UI activity indicators.
18
+ *
19
+ * The monitor is lazy: it only runs the analysis loop while at least one
20
+ * subscriber is attached. Call {@link dispose} when the stream is gone or
21
+ * the consumer goes away.
22
+ */
23
+ export declare class AudioLevelMonitor {
24
+ private context;
25
+ private analyser;
26
+ private source;
27
+ private buffer;
28
+ private timer;
29
+ private subscribers;
30
+ private currentLevel;
31
+ private disposed;
32
+ private readonly ownsContext;
33
+ private readonly updateIntervalMs;
34
+ private readonly logger?;
35
+ constructor(stream: MediaStream, options?: AudioLevelMonitorOptions);
36
+ /** Returns the most recent level computed by the monitor (0..1). */
37
+ get level(): number;
38
+ /**
39
+ * Subscribe for level updates. The callback fires immediately with the
40
+ * current level, then at {@link AudioLevelMonitorOptions.updateIntervalMs}.
41
+ * Returns an unsubscribe function.
42
+ */
43
+ subscribe(callback: LevelCallback): () => void;
44
+ dispose(): void;
45
+ private startLoop;
46
+ private stopLoop;
47
+ private tick;
48
+ private cleanup;
49
+ }
50
+ export {};
51
+ //# sourceMappingURL=AudioLevelMonitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioLevelMonitor.d.ts","sourceRoot":"","sources":["../../src/media/AudioLevelMonitor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAgBlD,MAAM,WAAW,wBAAwB;IACrC,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,uCAAuC;IACvC,MAAM,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;AAE7C;;;;;;;GAOG;AACH,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,MAAM,CAA2C;IACzD,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAiB;gBAE7B,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,wBAA6B;IA0CvE,oEAAoE;IACpE,IAAI,KAAK,IAAI,MAAM,CAElB;IAED;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,IAAI;IAkB9C,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,IAAI;IA0BZ,OAAO,CAAC,OAAO;CAiBlB"}
@@ -0,0 +1,179 @@
1
+ /** Update frequency for audio level subscribers. 10 Hz pairs well with 100 ms CSS transitions. */
2
+ const DEFAULT_UPDATE_INTERVAL_MS = 100;
3
+ /** Default FFT size — small for low CPU; we only need a coarse RMS. */
4
+ const DEFAULT_FFT_SIZE = 1024;
5
+ /** Default smoothing applied by the analyser node (0..1). */
6
+ const DEFAULT_SMOOTHING = 0.5;
7
+ /** dBFS at which the indicator reads zero. Quieter than this is treated as silence. */
8
+ const NOISE_FLOOR_DB = -60;
9
+ /** dBFS at which the indicator reads full. Normal speech peaks around -20 to -15 dBFS. */
10
+ const SPEECH_PEAK_DB = -15;
11
+ /** Attack/release smoothing across ticks (0..1). Higher = stickier; 0 = no smoothing. */
12
+ const ATTACK_SMOOTHING = 0.4;
13
+ const RELEASE_SMOOTHING = 0.7;
14
+ /**
15
+ * Computes a normalized speech audio level (0..1) from a MediaStream's audio
16
+ * track using the Web Audio API. Use it to drive UI activity indicators.
17
+ *
18
+ * The monitor is lazy: it only runs the analysis loop while at least one
19
+ * subscriber is attached. Call {@link dispose} when the stream is gone or
20
+ * the consumer goes away.
21
+ */
22
+ export class AudioLevelMonitor {
23
+ context = null;
24
+ analyser = null;
25
+ source = null;
26
+ buffer = null;
27
+ timer = null;
28
+ subscribers = new Set();
29
+ currentLevel = 0;
30
+ disposed = false;
31
+ ownsContext;
32
+ updateIntervalMs;
33
+ logger;
34
+ constructor(stream, options = {}) {
35
+ this.updateIntervalMs = options.updateIntervalMs ?? DEFAULT_UPDATE_INTERVAL_MS;
36
+ this.logger = options.logger;
37
+ this.ownsContext = !options.audioContext;
38
+ const Ctx = typeof globalThis !== 'undefined'
39
+ ? (globalThis
40
+ .AudioContext
41
+ ?? globalThis.webkitAudioContext)
42
+ : undefined;
43
+ if (!Ctx && !options.audioContext) {
44
+ this.logger?.log('debug', 'AudioLevelMonitor', 'AudioContext unavailable; monitor will report zero level');
45
+ return;
46
+ }
47
+ if (stream.getAudioTracks().length === 0) {
48
+ this.logger?.log('debug', 'AudioLevelMonitor', 'Stream has no audio tracks');
49
+ return;
50
+ }
51
+ try {
52
+ this.context = options.audioContext ?? new Ctx();
53
+ this.analyser = this.context.createAnalyser();
54
+ this.analyser.fftSize = options.fftSize ?? DEFAULT_FFT_SIZE;
55
+ this.analyser.smoothingTimeConstant = options.smoothing ?? DEFAULT_SMOOTHING;
56
+ this.source = this.context.createMediaStreamSource(stream);
57
+ this.source.connect(this.analyser);
58
+ this.buffer = new Uint8Array(new ArrayBuffer(this.analyser.fftSize));
59
+ // Browsers may create the context in a suspended state until a user gesture;
60
+ // resume it so analysis starts producing samples immediately.
61
+ if (this.context.state === 'suspended') {
62
+ void this.context.resume().catch((err) => {
63
+ this.logger?.log('debug', 'AudioLevelMonitor', `resume() failed: ${err}`);
64
+ });
65
+ }
66
+ }
67
+ catch (err) {
68
+ this.logger?.log('warning', 'AudioLevelMonitor', `Failed to attach to stream: ${err}`);
69
+ this.cleanup();
70
+ }
71
+ }
72
+ /** Returns the most recent level computed by the monitor (0..1). */
73
+ get level() {
74
+ return this.currentLevel;
75
+ }
76
+ /**
77
+ * Subscribe for level updates. The callback fires immediately with the
78
+ * current level, then at {@link AudioLevelMonitorOptions.updateIntervalMs}.
79
+ * Returns an unsubscribe function.
80
+ */
81
+ subscribe(callback) {
82
+ if (this.disposed) {
83
+ callback(0);
84
+ return () => { };
85
+ }
86
+ this.subscribers.add(callback);
87
+ callback(this.currentLevel);
88
+ if (this.analyser && this.subscribers.size === 1) {
89
+ this.startLoop();
90
+ }
91
+ return () => {
92
+ this.subscribers.delete(callback);
93
+ if (this.subscribers.size === 0) {
94
+ this.stopLoop();
95
+ }
96
+ };
97
+ }
98
+ dispose() {
99
+ if (this.disposed)
100
+ return;
101
+ this.disposed = true;
102
+ this.cleanup();
103
+ }
104
+ startLoop() {
105
+ if (this.timer !== null)
106
+ return;
107
+ const setIntervalFn = typeof globalThis !== 'undefined' && typeof globalThis.setInterval === 'function'
108
+ ? globalThis.setInterval.bind(globalThis)
109
+ : null;
110
+ if (!setIntervalFn)
111
+ return;
112
+ this.timer = setIntervalFn(() => this.tick(), this.updateIntervalMs);
113
+ }
114
+ stopLoop() {
115
+ if (this.timer === null)
116
+ return;
117
+ const clearIntervalFn = typeof globalThis !== 'undefined' && typeof globalThis.clearInterval === 'function'
118
+ ? globalThis.clearInterval.bind(globalThis)
119
+ : null;
120
+ clearIntervalFn?.(this.timer);
121
+ this.timer = null;
122
+ }
123
+ tick() {
124
+ if (this.disposed || !this.analyser || !this.buffer)
125
+ return;
126
+ if (this.context?.state === 'suspended') {
127
+ void this.context.resume().catch(() => { });
128
+ }
129
+ this.analyser.getByteTimeDomainData(this.buffer);
130
+ let sumSquares = 0;
131
+ for (let i = 0; i < this.buffer.length; i++) {
132
+ const sample = (this.buffer[i] - 128) / 128;
133
+ sumSquares += sample * sample;
134
+ }
135
+ const rms = Math.sqrt(sumSquares / this.buffer.length);
136
+ // Map RMS to dBFS, then to a perceptual 0..1 between the noise floor and speech peak.
137
+ const dbfs = rms > 0 ? 20 * Math.log10(rms) : NOISE_FLOOR_DB;
138
+ const target = Math.max(0, Math.min(1, (dbfs - NOISE_FLOOR_DB) / (SPEECH_PEAK_DB - NOISE_FLOOR_DB)));
139
+ // Asymmetric smoothing: snap up quickly (attack), decay slowly (release).
140
+ const smoothing = target > this.currentLevel ? ATTACK_SMOOTHING : RELEASE_SMOOTHING;
141
+ const level = this.currentLevel * smoothing + target * (1 - smoothing);
142
+ this.currentLevel = level;
143
+ this.subscribers.forEach((cb) => {
144
+ try {
145
+ cb(level);
146
+ }
147
+ catch (err) {
148
+ this.logger?.log('warning', 'AudioLevelMonitor', `Subscriber threw: ${err}`);
149
+ }
150
+ });
151
+ }
152
+ cleanup() {
153
+ this.stopLoop();
154
+ if (this.source) {
155
+ try {
156
+ this.source.disconnect();
157
+ }
158
+ catch { /* ignore */ }
159
+ this.source = null;
160
+ }
161
+ if (this.analyser) {
162
+ try {
163
+ this.analyser.disconnect();
164
+ }
165
+ catch { /* ignore */ }
166
+ this.analyser = null;
167
+ }
168
+ if (this.context && this.ownsContext) {
169
+ try {
170
+ void this.context.close();
171
+ }
172
+ catch { /* ignore */ }
173
+ }
174
+ this.context = null;
175
+ this.buffer = null;
176
+ this.subscribers.clear();
177
+ }
178
+ }
179
+ //# sourceMappingURL=AudioLevelMonitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioLevelMonitor.js","sourceRoot":"","sources":["../../src/media/AudioLevelMonitor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,137 @@
1
+ import type { RoomState, SignalingMessage } from '../signaling/types.js';
2
+ import type { ConnectionStatus, SerenadaLogger } from '../types.js';
3
+ export interface MediaEngineConfig {
4
+ turnsOnly?: boolean;
5
+ logger?: SerenadaLogger;
6
+ /** Initial camera facing mode. Defaults to `'user'` (selfie). */
7
+ initialFacingMode?: 'user' | 'environment';
8
+ /** When `false`, media starts audio-only and camera is requested on first video enable. */
9
+ initialVideoEnabled?: boolean;
10
+ /** When `false`, the camera is never requested and video is always off. */
11
+ videoCaptureSupported?: boolean;
12
+ }
13
+ export declare class MediaEngine {
14
+ localStream: MediaStream | null;
15
+ remoteStreams: Map<string, MediaStream>;
16
+ isScreenSharing: boolean;
17
+ canScreenShare: boolean;
18
+ facingMode: 'user' | 'environment';
19
+ hasMultipleCameras: boolean;
20
+ readonly videoCaptureSupported: boolean;
21
+ iceConnectionState: RTCIceConnectionState;
22
+ connectionState: RTCPeerConnectionState;
23
+ signalingState: RTCSignalingState;
24
+ connectionStatus: ConnectionStatus;
25
+ private peers;
26
+ private readonly initialVideoEnabled;
27
+ private lastInboundBytesByCid;
28
+ private rtcConfig;
29
+ private screenShareTrack;
30
+ private requestingMedia;
31
+ private destroyed;
32
+ private cameraRecoveryInFlight;
33
+ private mediaRequestId;
34
+ private retryingTimer;
35
+ private localVideoHeartbeatAt;
36
+ private localVideoHiddenAt;
37
+ private visibilityHandler;
38
+ private pageShowHandler;
39
+ private heartbeatInterval;
40
+ private onlineHandler;
41
+ private networkChangeHandler;
42
+ private deviceChangeHandler;
43
+ private turnsOnly;
44
+ private logger?;
45
+ private sendSignalingMessage;
46
+ private roomState;
47
+ private clientId;
48
+ private isSignalingConnected;
49
+ private onChange;
50
+ constructor(config: MediaEngineConfig, sendMessage: (type: string, payload?: Record<string, unknown>, to?: string) => void);
51
+ setOnChange(cb: () => void): void;
52
+ updateRoomState(state: RoomState | null, clientId: string | null): void;
53
+ updateSignalingConnected(connected: boolean): void;
54
+ setIceServers(iceServers: RTCIceServer[]): void;
55
+ handleSignalingReconnect(): void;
56
+ /**
57
+ * Schedule glare-safe ICE restart for a specific peer because the server
58
+ * told us the pair is dirty after the peer reattached (#1).
59
+ */
60
+ scheduleDirtyPairRestart(remoteCid: string): void;
61
+ processSignalingMessage(msg: SignalingMessage): void;
62
+ startLocalMedia(): Promise<MediaStream | null>;
63
+ stopLocalMedia(): void;
64
+ releaseVideoTrack(): Promise<void>;
65
+ reacquireVideoTrack(): Promise<void>;
66
+ startScreenShare(): Promise<void>;
67
+ stopScreenShare(): Promise<void>;
68
+ flipCamera(): Promise<void>;
69
+ getPeerConnections(): RTCPeerConnection[];
70
+ getPeerConnectionsMap(): Map<string, RTCPeerConnection>;
71
+ cleanupAllPeers(): void;
72
+ /**
73
+ * Sample inbound RTP `bytesReceived` per remote peer and return the CIDs
74
+ * whose totals advanced since the previous sample. Drives #3's
75
+ * `media_liveness{cids}` emission so the server can defer hard-eviction
76
+ * of suspended peers whose media is still being received locally.
77
+ *
78
+ * Conservative on first call (no baseline → empty result). Cleans up
79
+ * tracking for peers that have left.
80
+ */
81
+ getInboundFlowingCids(): Promise<string[]>;
82
+ destroy(): void;
83
+ /**
84
+ * Inspects each peer connection's currently-selected ICE candidate pair
85
+ * and returns true only when at least one peer exists and every peer's
86
+ * local candidate is direct (host / srflx / prflx). Returns false when
87
+ * any peer is relaying through TURN, when any stats query fails, or when
88
+ * there are no peers (TURN may be needed for a future join).
89
+ *
90
+ * We identify the active pair via `RTCTransportStats.selectedCandidatePairId`,
91
+ * with a fallback to the nominated+succeeded pair. We do NOT accept any
92
+ * arbitrary succeeded pair: after an ICE failover the old pair stays
93
+ * present as "succeeded" for a while, so reading it would lie about the
94
+ * current active path and wrongly suppress TURN refresh while media is
95
+ * actually relaying.
96
+ *
97
+ * Used by the TURN refresh gate: if all active media flows are direct,
98
+ * refreshing TURN credentials over signaling is unnecessary upkeep. This
99
+ * lets a P2P call survive indefinite signaling outages.
100
+ */
101
+ arePeerPathsAllDirect(): Promise<boolean>;
102
+ private isPeerOnDirectPath;
103
+ private syncPeers;
104
+ private getOrCreatePeer;
105
+ private cleanupPeer;
106
+ private clearPeerTimers;
107
+ private shouldIOffer;
108
+ private createOfferTo;
109
+ private scheduleIceRestart;
110
+ private triggerIceRestart;
111
+ private scheduleNonHostFallback;
112
+ private handleOfferFrom;
113
+ private handleAnswerFrom;
114
+ private handleIceFrom;
115
+ private updateAggregateState;
116
+ private updateConnectionStatusValue;
117
+ private resetConnectionStatusMachine;
118
+ private setConnectionRecovering;
119
+ private scheduleRetryingTransition;
120
+ private normalizeIceServers;
121
+ private applySpeechTrackHints;
122
+ private applyAudioSenderParameters;
123
+ private acquireCameraTrack;
124
+ private replaceVideoTrackOnAllPeers;
125
+ private swapLocalVideoTrack;
126
+ private ensureMediaTransceivers;
127
+ private findTransceiver;
128
+ private attachLocalTracksToPeer;
129
+ private attachLocalTrackToPeer;
130
+ private scheduleLocalTrackNegotiation;
131
+ private refreshLocalVideoTrack;
132
+ private detectCameras;
133
+ private setupEventListeners;
134
+ private removeEventListeners;
135
+ private notifyChange;
136
+ }
137
+ //# sourceMappingURL=MediaEngine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaEngine.d.ts","sourceRoot":"","sources":["../../src/media/MediaEngine.ts"],"names":[],"mappings":"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"}