Fix WebRTC state machine error in pooled services

When handling answered offers in pooled services, we were creating fresh
peer connections in "stable" state and trying to set the remote answer,
which caused "Cannot set remote answer in state stable" error.

Fixed by:
- Adding offerSdp to AnsweredOffer interface
- Passing original offer SDP through the offer pool
- Setting local description (offer) before remote description (answer)

This ensures the peer connection is in "have-local-offer" state before
applying the answer, satisfying WebRTC's state machine requirements.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-05 19:51:09 +01:00
parent b2d42fa776
commit 4a6d0ee091
2 changed files with 17 additions and 3 deletions

View File

@@ -6,7 +6,8 @@ import { RondevuOffers, Offer } from './offers.js';
export interface AnsweredOffer { export interface AnsweredOffer {
offerId: string; offerId: string;
answererId: string; answererId: string;
sdp: string; sdp: string; // Answer SDP
offerSdp: string; // Original offer SDP
answeredAt: number; answeredAt: number;
} }
@@ -110,11 +111,18 @@ export class OfferPool {
// Process each answer // Process each answer
for (const answer of myAnswers) { for (const answer of myAnswers) {
// Notify ServicePool // Get the original offer
const offer = this.offers.get(answer.offerId);
if (!offer) {
continue; // Offer already consumed, skip
}
// Notify ServicePool with both answer and original offer SDP
await this.options.onAnswered({ await this.options.onAnswered({
offerId: answer.offerId, offerId: answer.offerId,
answererId: answer.answererId, answererId: answer.answererId,
sdp: answer.sdp, sdp: answer.sdp,
offerSdp: offer.sdp,
answeredAt: answer.answeredAt answeredAt: answer.answeredAt
}); });

View File

@@ -241,7 +241,13 @@ export class ServicePool {
peer.role = 'offerer'; peer.role = 'offerer';
peer.offerId = answer.offerId; peer.offerId = answer.offerId;
// Set remote description (the answer) // Set local description (the original offer) first
await peer.pc.setLocalDescription({
type: 'offer',
sdp: answer.offerSdp
});
// Now set remote description (the answer)
await peer.pc.setRemoteDescription({ await peer.pc.setRemoteDescription({
type: 'answer', type: 'answer',
sdp: answer.sdp sdp: answer.sdp