Improve trickle ICE with early candidate buffering

- Buffer ICE candidates generated before offerId is set
- Flush buffered candidates immediately after offerId is set
- Continue sending candidates as they arrive (true trickle ICE)
- Prevents losing early ICE candidates during setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-14 19:01:49 +01:00
parent c202e1c627
commit cd78a16c66

View File

@@ -60,6 +60,7 @@ export class RondevuConnection {
private lastIceTimestamp: number = Date.now();
private eventListeners: Map<keyof RondevuConnectionEvents, Set<Function>> = new Map();
private dataChannel?: RTCDataChannel;
private pendingIceCandidates: string[] = [];
/**
* Current connection state
@@ -101,12 +102,20 @@ export class RondevuConnection {
*/
private setupPeerConnection(): void {
this.pc.onicecandidate = async (event) => {
if (event.candidate && this.offerId) {
if (event.candidate) {
const candidateString = event.candidate.candidate;
if (this.offerId) {
// offerId is set, send immediately (trickle ICE)
try {
await this.offersApi.addIceCandidates(this.offerId, [event.candidate.candidate]);
await this.offersApi.addIceCandidates(this.offerId, [candidateString]);
} catch (err) {
console.error('Error sending ICE candidate:', err);
}
} else {
// offerId not set yet, buffer the candidate
this.pendingIceCandidates.push(candidateString);
}
}
};
@@ -141,6 +150,20 @@ export class RondevuConnection {
};
}
/**
* Flush buffered ICE candidates (trickle ICE support)
*/
private async flushPendingIceCandidates(): Promise<void> {
if (this.pendingIceCandidates.length > 0 && this.offerId) {
try {
await this.offersApi.addIceCandidates(this.offerId, this.pendingIceCandidates);
this.pendingIceCandidates = [];
} catch (err) {
console.error('Error flushing pending ICE candidates:', err);
}
}
}
/**
* Create an offer and advertise on topics
*/
@@ -168,6 +191,9 @@ export class RondevuConnection {
this.offerId = offers[0].id;
// Flush any ICE candidates that were generated during offer creation
await this.flushPendingIceCandidates();
// Start polling for answers
this.startAnswerPolling();
@@ -198,6 +224,9 @@ export class RondevuConnection {
// This prevents a race condition where ICE candidates arrive before answer is registered
this.offerId = offerId;
// Flush any ICE candidates that were generated during answer creation
await this.flushPendingIceCandidates();
// Start polling for ICE candidates
this.startIcePolling();
}