@xtr-dev/rondevu-client 0.21.12 → 0.21.13

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.
@@ -32,9 +32,9 @@ export declare class AnswererConnection extends RondevuConnection {
32
32
  */
33
33
  initialize(): Promise<void>;
34
34
  /**
35
- * Handle local ICE candidate generation
35
+ * Send buffered ICE candidates to the server in a single batch
36
36
  */
37
- protected onLocalIceCandidate(candidate: RTCIceCandidate): void;
37
+ protected sendBufferedIceCandidates(candidates: RTCIceCandidate[]): void;
38
38
  /**
39
39
  * Get the API instance
40
40
  */
@@ -51,22 +51,21 @@ export class AnswererConnection extends RondevuConnection {
51
51
  this.debug('Answer sent successfully');
52
52
  }
53
53
  /**
54
- * Handle local ICE candidate generation
54
+ * Send buffered ICE candidates to the server in a single batch
55
55
  */
56
- onLocalIceCandidate(candidate) {
57
- this.debug('Generated local ICE candidate');
56
+ sendBufferedIceCandidates(candidates) {
57
+ if (candidates.length === 0)
58
+ return;
59
+ this.debug(`Sending ${candidates.length} ICE candidates in batch`);
58
60
  // For answerer, we add ICE candidates to the offer
59
61
  // The server will make them available for the offerer to poll
60
- this.api
61
- .addOfferIceCandidates(this.offerId, [
62
- {
63
- candidate: candidate.candidate,
64
- sdpMLineIndex: candidate.sdpMLineIndex,
65
- sdpMid: candidate.sdpMid,
66
- },
67
- ])
68
- .catch(error => {
69
- this.debug('Failed to send ICE candidate:', error);
62
+ const apiCandidates = candidates.map(c => ({
63
+ candidate: c.candidate,
64
+ sdpMLineIndex: c.sdpMLineIndex,
65
+ sdpMid: c.sdpMid,
66
+ }));
67
+ this.api.addOfferIceCandidates(this.offerId, apiCandidates).catch(error => {
68
+ this.debug('Failed to send ICE candidates:', error);
70
69
  });
71
70
  }
72
71
  /**
@@ -27,6 +27,9 @@ export declare abstract class RondevuConnection extends EventEmitter<ConnectionE
27
27
  protected lastIcePollTime: number;
28
28
  protected answerProcessed: boolean;
29
29
  protected answerSdpFingerprint: string | null;
30
+ protected iceCandidateBuffer: RTCIceCandidate[];
31
+ protected iceCandidateFlushTimer: ReturnType<typeof setTimeout> | null;
32
+ protected static readonly ICE_BUFFER_DELAY_MS = 20;
30
33
  constructor(rtcConfig?: RTCConfiguration | undefined, userConfig?: Partial<ConnectionConfig>, webrtcAdapter?: WebRTCAdapter);
31
34
  /**
32
35
  * Transition to a new state and emit events
@@ -42,8 +45,17 @@ export declare abstract class RondevuConnection extends EventEmitter<ConnectionE
42
45
  protected setupDataChannelHandlers(dc: RTCDataChannel): void;
43
46
  /**
44
47
  * Handle local ICE candidate generation
48
+ * Buffers candidates for batched sending to reduce server requests
45
49
  */
46
50
  protected handleIceCandidate(event: RTCPeerConnectionIceEvent): void;
51
+ /**
52
+ * Buffer an ICE candidate for batched sending
53
+ */
54
+ protected bufferIceCandidate(candidate: RTCIceCandidate): void;
55
+ /**
56
+ * Flush buffered ICE candidates to the server
57
+ */
58
+ protected flushIceCandidates(): void;
47
59
  /**
48
60
  * Handle ICE connection state changes (primary state driver)
49
61
  */
@@ -166,6 +178,6 @@ export declare abstract class RondevuConnection extends EventEmitter<ConnectionE
166
178
  * Debug logging helper
167
179
  */
168
180
  protected debug(...args: unknown[]): void;
169
- protected abstract onLocalIceCandidate(candidate: RTCIceCandidate): void;
181
+ protected abstract sendBufferedIceCandidates(candidates: RTCIceCandidate[]): void;
170
182
  protected abstract attemptReconnect(): void;
171
183
  }
@@ -32,6 +32,9 @@ export class RondevuConnection extends EventEmitter {
32
32
  // Answer fingerprinting (for offerer)
33
33
  this.answerProcessed = false;
34
34
  this.answerSdpFingerprint = null;
35
+ // ICE candidate buffering for batched sending
36
+ this.iceCandidateBuffer = [];
37
+ this.iceCandidateFlushTimer = null;
35
38
  this.config = mergeConnectionConfig(userConfig);
36
39
  this.webrtcAdapter = webrtcAdapter || new BrowserWebRTCAdapter();
37
40
  // Initialize message buffer if enabled
@@ -102,12 +105,45 @@ export class RondevuConnection extends EventEmitter {
102
105
  }
103
106
  /**
104
107
  * Handle local ICE candidate generation
108
+ * Buffers candidates for batched sending to reduce server requests
105
109
  */
106
110
  handleIceCandidate(event) {
107
111
  this.emit('ice:candidate:local', event.candidate);
108
112
  if (event.candidate) {
109
- this.onLocalIceCandidate(event.candidate);
113
+ this.bufferIceCandidate(event.candidate);
110
114
  }
115
+ else {
116
+ // null candidate means ICE gathering complete - flush any remaining
117
+ this.flushIceCandidates();
118
+ }
119
+ }
120
+ /**
121
+ * Buffer an ICE candidate for batched sending
122
+ */
123
+ bufferIceCandidate(candidate) {
124
+ this.iceCandidateBuffer.push(candidate);
125
+ // Reset flush timer
126
+ if (this.iceCandidateFlushTimer) {
127
+ clearTimeout(this.iceCandidateFlushTimer);
128
+ }
129
+ this.iceCandidateFlushTimer = setTimeout(() => {
130
+ this.flushIceCandidates();
131
+ }, RondevuConnection.ICE_BUFFER_DELAY_MS);
132
+ }
133
+ /**
134
+ * Flush buffered ICE candidates to the server
135
+ */
136
+ flushIceCandidates() {
137
+ if (this.iceCandidateFlushTimer) {
138
+ clearTimeout(this.iceCandidateFlushTimer);
139
+ this.iceCandidateFlushTimer = null;
140
+ }
141
+ if (this.iceCandidateBuffer.length === 0)
142
+ return;
143
+ const candidates = [...this.iceCandidateBuffer];
144
+ this.iceCandidateBuffer = [];
145
+ this.debug(`Flushing ${candidates.length} buffered ICE candidates`);
146
+ this.sendBufferedIceCandidates(candidates);
111
147
  }
112
148
  /**
113
149
  * Handle ICE connection state changes (primary state driver)
@@ -496,6 +532,12 @@ export class RondevuConnection extends EventEmitter {
496
532
  this.cancelReconnect();
497
533
  // Stop ICE polling
498
534
  this.stopIcePolling();
535
+ // Clear ICE candidate buffer
536
+ if (this.iceCandidateFlushTimer) {
537
+ clearTimeout(this.iceCandidateFlushTimer);
538
+ this.iceCandidateFlushTimer = null;
539
+ }
540
+ this.iceCandidateBuffer = [];
499
541
  // Close data channel
500
542
  if (this.dc) {
501
543
  this.dc.onopen = null;
@@ -533,3 +575,4 @@ export class RondevuConnection extends EventEmitter {
533
575
  }
534
576
  }
535
577
  }
578
+ RondevuConnection.ICE_BUFFER_DELAY_MS = 20; // Buffer for 20ms before sending
@@ -54,9 +54,9 @@ export declare class OffererConnection extends RondevuConnection {
54
54
  */
55
55
  private hashSdp;
56
56
  /**
57
- * Handle local ICE candidate generation
57
+ * Send buffered ICE candidates to the server in a single batch
58
58
  */
59
- protected onLocalIceCandidate(candidate: RTCIceCandidate): void;
59
+ protected sendBufferedIceCandidates(candidates: RTCIceCandidate[]): void;
60
60
  /**
61
61
  * Get the API instance
62
62
  */
@@ -193,21 +193,20 @@ export class OffererConnection extends RondevuConnection {
193
193
  }
194
194
  }
195
195
  /**
196
- * Handle local ICE candidate generation
196
+ * Send buffered ICE candidates to the server in a single batch
197
197
  */
198
- onLocalIceCandidate(candidate) {
199
- this.debug('Generated local ICE candidate');
200
- // Send ICE candidate to server
201
- this.api
202
- .addOfferIceCandidates(this.offerId, [
203
- {
204
- candidate: candidate.candidate,
205
- sdpMLineIndex: candidate.sdpMLineIndex,
206
- sdpMid: candidate.sdpMid,
207
- },
208
- ])
209
- .catch(error => {
210
- this.debug('Failed to send ICE candidate:', error);
198
+ sendBufferedIceCandidates(candidates) {
199
+ if (candidates.length === 0)
200
+ return;
201
+ this.debug(`Sending ${candidates.length} ICE candidates in batch`);
202
+ // Convert to API format and send in single request
203
+ const apiCandidates = candidates.map(c => ({
204
+ candidate: c.candidate,
205
+ sdpMLineIndex: c.sdpMLineIndex,
206
+ sdpMid: c.sdpMid,
207
+ }));
208
+ this.api.addOfferIceCandidates(this.offerId, apiCandidates).catch(error => {
209
+ this.debug('Failed to send ICE candidates:', error);
211
210
  });
212
211
  }
213
212
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtr-dev/rondevu-client",
3
- "version": "0.21.12",
3
+ "version": "0.21.13",
4
4
  "description": "TypeScript client for Rondevu with durable WebRTC connections, automatic reconnection, and message queuing",
5
5
  "type": "module",
6
6
  "main": "dist/core/index.js",