Quay lại
React WebRTC: Cách Fix Lỗi Failed to set remote answer sdp

React WebRTC: Cách Fix Lỗi Failed to set remote answer sdp

Mình đã mất khá nhiều thời gian để debug lỗi InvalidStateError: Failed to set remote answer sdp trong một ứng dụng React WebRTC sử dụng Simple-Peer và Socket.IO. Vấn đề thực sự không nằm ở SDP, mà đến từ duplicated signaling events, signaling state sai và cách React xử lý lifecycle. Đây là nguyên nhân thật sự và cách fix đã hoạt động với mình.

Nguyen Thanh Nam1 giờ trước5 phút đọc35 lượt xem

Nếu bạn đang build một ứng dụng video call bằng React và WebRTC rồi đột nhiên gặp lỗi:

InvalidStateError: Failed to set remote answer sdp

thì bạn không phải người duy nhất đâu.

Mình đã mất khá nhiều thời gian để debug lỗi này khi xây dựng một ứng dụng video call sử dụng React, WebRTC, Simple-Peer và Socket.IO. Ban đầu mọi thứ trông hoàn toàn bình thường:

  • signaling server hoạt động
  • peer kết nối được
  • ICE candidates được exchange đầy đủ
  • SDP nhìn không có gì sai

Nhưng browser vẫn random quăng ra lỗi.

Điều khó chịu nhất là message này gần như không nói rõ nguyên nhân thật sự nằm ở đâu.

Trong trường hợp của mình, vấn đề thực tế liên quan đến WebRTC signaling state và việc xử lý SDP answer bị lặp.


Tại sao lỗi này xảy ra?

Lỗi này thường xuất hiện khi bạn cố gắng set một remote answer SDP trong lúc peer connection đang ở sai signaling state.

Nói đơn giản hơn:

WebRTC nhận được SDP answer vào thời điểm mà nó không mong đợi.

Điều này thường xảy ra khi:

  • cùng một answer bị xử lý nhiều lần
  • cả hai peer cùng tạo offer
  • socket event bị duplicate
  • React component re-render và tạo lại peer ngoài ý muốn
  • signaling flow chạy sai thứ tự

Vấn đề thực tế của mình

Trong project của mình, mình vô tình xử lý socket event answer nhiều hơn một lần.

Kết quả:

  1. lần đầu setRemoteDescription() chạy thành công
  2. lần thứ hai cố apply lại cùng một SDP
  3. WebRTC reject ngay với lỗi:
Failed to set remote answer sdp

Lúc đầu mình nghĩ:

  • ICE server có vấn đề
  • STUN/TURN config bị sai
  • SDP format không hợp lệ

Nhưng cuối cùng không phải mấy thứ đó.


Cách mình fix lỗi

Cách fix thực ra khá đơn giản:

  • đảm bảo answer chỉ được xử lý một lần
  • kiểm tra signaling state trước khi apply SDP
  • tránh duplicate socket listeners

Implementation dễ gây lỗi

Đây là kiểu code rất dễ gây ra vấn đề:

socket.on("answer", (answer) => {
  peer.signal(answer);
});

Nhìn thì vô hại, nhưng nếu:

  • listener bị register nhiều lần
  • React re-render ngoài ý muốn
  • cùng một event bị emit lại

thì peer.signal(answer) có thể chạy thêm lần nữa khi connection đã ở trạng thái stable.


Cách fix tốt hơn

Mình fix bằng cách kiểm tra signaling state trước khi signal:

socket.on("answer", (answer) => {
  if (peer._pc.signalingState !== "stable") {
    peer.signal(answer);
  }
});

Ngoài ra mình cũng cleanup socket listeners cẩn thận:

useEffect(() => {
  socket.on("answer", handleAnswer);
 
  return () => {
    socket.off("answer", handleAnswer);
  };
}, []);

Sau khi làm vậy thì lỗi biến mất hoàn toàn.


Một nguyên nhân phổ biến khác trong React

React Strict Mode cũng có thể khiến lỗi này khó chịu hơn rất nhiều trong môi trường development.

Trong development mode, React có thể cố tình chạy effects hai lần.

Điều đó đồng nghĩa với việc:

  • peer có thể bị tạo hai lần
  • socket listeners bị duplicate
  • SDP answer bị xử lý lặp

Nếu bạn chỉ gặp lỗi ở môi trường development nhưng production thì không, đây là dấu hiệu rất đáng nghi.


Những thứ nên kiểm tra

Nếu bạn vẫn đang bị mắc kẹt, hãy kiểm tra kỹ các thứ sau.

1. Tránh duplicate socket listeners

Không nên:

socket.on("answer", callback);

ở những component re-render thường xuyên.

Nên:

  • dùng useEffect
  • cleanup listeners đầy đủ
  • tránh register event lặp

2. Đừng tạo lại peer ngoài ý muốn

Một lỗi rất phổ biến:

const peer = new Peer();

ngay trong render logic.

Hãy dùng:

  • useRef
  • stable initialization
  • cleanup hợp lý

thay vào đó.


3. Tránh signal nhiều lần

Trước khi gọi:

peer.signal(data);

hãy đảm bảo:

  • peer vẫn còn tồn tại
  • signaling state hợp lệ
  • SDP chưa bị apply trước đó

4. Kiểm tra signaling flow

Thứ tự đúng thường là:

  1. tạo offer
  2. gửi offer
  3. tạo answer
  4. trả answer
  5. apply answer đúng một lần

Nếu events đến sai thứ tự, WebRTC sẽ rất dễ “nổi điên”.


Tip debug giúp mình tìm ra lỗi

Thứ giúp mình debug nhanh nhất là log signaling state trước khi apply SDP:

console.log(peer._pc.signalingState);

Các state phổ biến:

  • stable
  • have-local-offer
  • have-remote-offer

Nếu bạn cố apply answer trong khi state đã là stable, browser rất dễ quăng lỗi này.


Kết luận

Con bug này khó chịu hơn mình nghĩ rất nhiều vì nguyên nhân thực sự không nằm ở SDP.

Vấn đề thật sự là:

  • duplicated events
  • signaling flow sai
  • React lifecycle behavior

Nếu bạn đang dùng:

  • React
  • WebRTC
  • Simple-Peer
  • Socket.IO

thì khả năng rất cao lỗi của bạn cũng liên quan đến signaling state management.

Hy vọng bài viết này giúp bạn tiết kiệm được vài tiếng debug vô ích.

Thẻ

Bài viết liên quan