Blog
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 Nam01:10 CH 26/05/20265 phút đọc63 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

Vì sao design và engineering vẫn luôn lệch khỏi nhau trong các product team hiện đại
BLOGdesignengineering

Vì sao design và engineering vẫn luôn lệch khỏi nhau trong các product team hiện đại

Các product team hiện đại vẫn luôn gặp khó khăn với khoảng cách giữa design intent và sản phẩm thực tế được ship. Bài viết phân tích vì sao designer và engineer thường nhìn sản phẩm theo những cách khác nhau, cách handoff culture tạo ra sự lệch pha, và tại sao design engineering có thể là chìa khóa để xây dựng trải nghiệm số đồng nhất hơn.

03:27 CH 16/05/20264
Cách Designer Collaboration Tốt Hơn Với Engineer
BLOGdesignengineering

Cách Designer Collaboration Tốt Hơn Với Engineer

Những sản phẩm tốt hiếm khi được tạo ra chỉ bởi design hoặc engineering riêng lẻ. Bài viết này chia sẻ những cách thực tế giúp designer làm việc hiệu quả hơn với engineer, từ việc hiểu technical constraint, giao tiếp bằng cùng “ngôn ngữ” cho tới cải thiện QA và product workflow.

01:36 CH 16/05/20268
Vì sao những product team tốt nhất đang dần từ bỏ design handoff
BLOGdesignengineering

Vì sao những product team tốt nhất đang dần từ bỏ design handoff

Design handoff truyền thống thường tạo ra khoảng cách giữa designer và developer, dẫn tới workflow chậm chạp, implementation issue và sản phẩm dần lệch khỏi design intent ban đầu. Bài viết này phân tích vì sao nhiều product team hiện đại đang thay thế handoff culture bằng collaboration liên tục, shared prototype và workflow gắn kết hơn giữa design và engineering.

01:23 CH 16/05/202616