diff --git a/app/javascript/dashboard/composables/useWhatsappCallSession.js b/app/javascript/dashboard/composables/useWhatsappCallSession.js index 5ab0f60de..26b4c7144 100644 --- a/app/javascript/dashboard/composables/useWhatsappCallSession.js +++ b/app/javascript/dashboard/composables/useWhatsappCallSession.js @@ -143,9 +143,15 @@ function waitForIceGatheringComplete(pc) { }); } -// ── Server-relay mode: detect by absence of sdpOffer in incoming call data ── +// ── Server-relay mode detection ── +// Prefer the explicit flag set by Rails whenever it's available (call object +// from GET /whatsapp_calls/:id, inbox serializer, or the incoming ActionCable +// broadcast). Fall back to the presence of sdpOffer so legacy deployments keep +// working when the field isn't set. function isServerRelayCall(call) { - return !call.sdpOffer; + if (call?.mediaServerEnabled === true) return true; + if (call?.mediaServerEnabled === false) return false; + return !call?.sdpOffer; } /** @@ -290,6 +296,7 @@ export async function acceptWhatsappCallById(callId) { conversationId: data.conversation_id, sdpOffer: data.sdp_offer, iceServers: data.ice_servers, + mediaServerEnabled: data.media_server_enabled, caller: data.caller, }; callsStore.addIncomingCall(call); diff --git a/app/javascript/dashboard/helper/actionCable.js b/app/javascript/dashboard/helper/actionCable.js index b34c1cc5f..0393f6603 100644 --- a/app/javascript/dashboard/helper/actionCable.js +++ b/app/javascript/dashboard/helper/actionCable.js @@ -226,6 +226,7 @@ class ActionCableConnector extends BaseActionCableConnector { caller: data.caller, sdpOffer: data.sdp_offer || null, iceServers: data.ice_servers || null, + mediaServerEnabled: data.media_server_enabled, }); }; diff --git a/enterprise/app/controllers/api/v1/accounts/whatsapp_calls_controller.rb b/enterprise/app/controllers/api/v1/accounts/whatsapp_calls_controller.rb index a779cda97..dad947e88 100644 --- a/enterprise/app/controllers/api/v1/accounts/whatsapp_calls_controller.rb +++ b/enterprise/app/controllers/api/v1/accounts/whatsapp_calls_controller.rb @@ -14,8 +14,14 @@ class Api::V1::Accounts::WhatsappCallsController < Api::V1::Accounts::BaseContro conversation_id: @call.conversation_id, inbox_id: @call.inbox_id, message_id: @call.message_id, - sdp_offer: @call.ringing? ? @call.sdp_offer : nil, - ice_servers: @call.ice_servers, + # In server-relay mode the browser must not talk WebRTC to Meta directly + # — the media server owns that peer connection. Omitting sdp_offer forces + # the FE's isServerRelayCall() check to return true so the accept flow + # waits for the whatsapp_call.agent_offer broadcast from Rails instead of + # negotiating straight with Meta. + sdp_offer: @call.ringing? && !Call.media_server_enabled? ? @call.sdp_offer : nil, + ice_servers: Call.media_server_enabled? ? [] : @call.ice_servers, + media_server_enabled: Call.media_server_enabled?, caller: caller_info } end diff --git a/enterprise/app/services/whatsapp/incoming_call_service.rb b/enterprise/app/services/whatsapp/incoming_call_service.rb index ee498725c..12ef23fcd 100644 --- a/enterprise/app/services/whatsapp/incoming_call_service.rb +++ b/enterprise/app/services/whatsapp/incoming_call_service.rb @@ -157,6 +157,7 @@ class Whatsapp::IncomingCallService direction: call.direction_label, inbox_id: call.inbox_id, conversation_id: call.conversation_id, + media_server_enabled: Call.media_server_enabled?, caller: { name: contact.name, phone: contact.phone_number,