From 3c33d912df05b890ff571d9675bb7f49677d7a1b Mon Sep 17 00:00:00 2001 From: Tanmay Deep Sharma Date: Thu, 7 May 2026 19:57:18 +0700 Subject: [PATCH] fix(voice): persist late outbound SDP answers when ACCEPTED races connect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If status=ACCEPTED is processed before Meta's connect webhook, the call is already in_progress when accept_outbound_call runs, and the previous guard dropped the SDP answer — leaving the browser without the data it needs to complete the WebRTC handshake. Gate on a stored sdp_answer instead of in_progress so out-of-order delivery still persists and broadcasts the answer (and connect retries stay idempotent). --- .../app/services/whatsapp/incoming_call_service.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/enterprise/app/services/whatsapp/incoming_call_service.rb b/enterprise/app/services/whatsapp/incoming_call_service.rb index c5621950f..772732e89 100644 --- a/enterprise/app/services/whatsapp/incoming_call_service.rb +++ b/enterprise/app/services/whatsapp/incoming_call_service.rb @@ -84,10 +84,15 @@ class Whatsapp::IncomingCallService # `connect` is the WebRTC tunnel-ready signal, not the pickup signal. Apply # Meta's SDP answer so the handshake completes during ringing; the call - # stays in `ringing` until status=ACCEPTED arrives. + # stays in `ringing` until status=ACCEPTED arrives. Don't gate on + # in_progress: an out-of-order ACCEPTED can flip status before connect is + # processed, and dropping the SDP answer would leave the browser without + # the data it needs to complete the handshake. Use the stored answer as + # the idempotency key instead. def accept_outbound_call(call, payload) call.with_lock do - next if call.in_progress? || call.terminal? + next if call.terminal? + next if call.meta&.dig('sdp_answer').present? # Pin setup:active so browsers don't renegotiate when Meta echoes actpass. sdp_answer = payload.dig(:session, :sdp)&.gsub('a=setup:actpass', 'a=setup:active')