I’ve implemented WhatsApp user initiated calling using WebRTC, nodeJS, ReactJS. Its working properly on local but not working on live, the i’m getting on both ends seems similar and normal, But on live the call the is getting auto hungup on after 20 seconds. On local its working Fine. Following is the code to handle user initiated calls from WhatsApp.
I’m following this documentation
https://developers.facebook.com/docs/whatsapp/cloud-api/calling/user-initiated-calls
const handleUserInitiatedCallRequest = async ({ req, res }) => {
let db;
try {
// Extract and validate webhook data
const change = req.body.entry?.[0]?.changes?.[0] || {};
const call = change?.value?.calls?.[0] || {};
const callId = call?.id;
const receivedSdp = call.session?.sdp;
const WHATSAPP_BUSINESS_ACCOUNT_ID =
change.value?.metadata?.phone_number_id;
let tenantIdRes = await getTenantIdFromUserMetaData(
`whatsapp_id`,
WHATSAPP_BUSINESS_ACCOUNT_ID
);
tenant_id = tenantIdRes?.tenant_id;
const io = getIO();
db = await getUserDBfromRequest({ tenant_id });
let contactDetails =
(await getChatUserDetailsById(db, call?.from, {
platform: "whatsapp",
})) || {};
if (!callId || !receivedSdp || !WHATSAPP_BUSINESS_ACCOUNT_ID) {
console.error("Missing required call data:", {
callId,
receivedSdp,
WHATSAPP_BUSINESS_ACCOUNT_ID,
chat_user: contactDetails,
});
return;
}
const callerName = call?.from || "Unknown";
const callerNumber = call?.from || "Unknown";
console.log(`Incoming WhatsApp call from ${callerName} (${callerNumber})`);
io.emit(`whatsapp_calling_incoming_request_${tenant_id}`, {
callId,
callerName,
callerNumber,
chat_user: contactDetails,
});
setActiveCalls({
callId,
value: {
whatsappOfferSdp: receivedSdp,
phone_number_id: WHATSAPP_BUSINESS_ACCOUNT_ID,
},
});
await initiateWebRTCBridge({ callId });
} catch (error) {
if (db) db.destroy();
console.error("Error handling call request:", getAxiosError(error));
}
};
async function initiateWebRTCBridge({ callId }) {
try {
const { getIO } = require("../../../../../sockets");
let io = getIO();
let browserOfferSdp = activeCalls[callId]?.browserOfferSdp;
let whatsappOfferSdp = activeCalls[callId]?.whatsappOfferSdp;
let browserSocket = io;
let whatsappPc = activeCalls[callId]?.whatsappPc;
if (!browserOfferSdp || !whatsappOfferSdp || !browserSocket) return;
// --- Setup browser peer connection ---
activeCalls[callId].browserPc = new RTCPeerConnection({
iceServers: STUN_SERVERS,
});
activeCalls[callId].browserStream = new MediaStream();
activeCalls[callId].browserPc.ontrack = (event) => {
console.log("Audio track received from browser.");
event.streams[0]
.getTracks()
.forEach((track) => activeCalls[callId].browserStream.addTrack(track));
};
activeCalls[callId].browserPc.onicecandidate = (event) => {
if (event.candidate) {
browserSocket.emit("whatsapp-calling-browser-candidate", {
candidate: event.candidate,
callId,
});
}
};
try {
sdpTransform.parse(sanitizeSdp(browserOfferSdp)); // pinpoints the bad line
} catch (e) {
console.error("Bad SDP from browser:", e);
}
const cleanSdp = sanitizeSdp(browserOfferSdp);
await activeCalls[callId].browserPc.setRemoteDescription(
new RTCSessionDescription(cleanSdp, "offer")
);
console.log("Browser offer SDP set as remote description.");
// --- Setup WhatsApp peer connection ---
whatsappPc = new RTCPeerConnection({ iceServers: STUN_SERVERS });
const waTrackPromise = new Promise((resolve, reject) => {
const timeout = setTimeout(
() => reject("Timed out waiting for WhatsApp track"),
10000
);
whatsappPc.ontrack = (event) => {
clearTimeout(timeout);
console.log("Audio track received from WhatsApp.");
whatsappStream = event.streams[0];
resolve();
};
whatsappPc.onicecandidate = (e) => {
console.log(
"[WA-PC] cand:",
e.candidate?.candidate || "end-of-candidates"
);
};
whatsappPc.oniceconnectionstatechange = () => {
console.log("[WA-PC] ice:", whatsappPc.iceConnectionState);
};
});
await whatsappPc.setRemoteDescription(
new RTCSessionDescription(whatsappOfferSdp, "offer")
);
console.log("WhatsApp offer SDP set as remote description.");
// Forward browser mic to WhatsApp
activeCalls[callId].browserStream?.getAudioTracks().forEach((track) => {
console.log(track, "<<<<<<<<<<<<<<<< sending track to whatsapp");
whatsappPc.addTrack(track, activeCalls[callId].browserStream);
});
console.log("Forwarded browser audio to WhatsApp.");
// Wait for WhatsApp to send audio
await waTrackPromise;
// Forward WhatsApp audio to browser
whatsappStream?.getAudioTracks().forEach((track) => {
console.log(track, "<<<<<<<<<<<<<<<< sending track to browser");
activeCalls[callId].browserPc.addTrack(track, whatsappStream);
});
// --- Create SDP answers for both peers ---
const browserAnswer = await activeCalls[callId].browserPc.createAnswer();
await activeCalls[callId].browserPc.setLocalDescription(browserAnswer);
browserSocket.emit("whatsapp-calling-browser-answer", {
sdp: browserAnswer.sdp,
callId,
});
console.log("Browser answer SDP created and sent.");
const waAnswer = await whatsappPc.createAnswer();
await whatsappPc.setLocalDescription(waAnswer);
const finalWaSdp = waAnswer.sdp.replace(
"a=setup:actpass",
"a=setup:active"
);
console.log("WhatsApp answer SDP prepared.");
// Send pre-accept, and only proceed with accept if successful
const preAcceptSuccess = await answerCallToWhatsApp(
callId,
finalWaSdp,
"pre_accept",
activeCalls?.[callId]?.phone_number_id
);
if (preAcceptSuccess) {
await Promise.race([
new Promise((r) => {
const h = () => {
if (
["connected", "completed"].includes(whatsappPc.iceConnectionState)
) {
whatsappPc.removeEventListener("iceconnectionstatechange", h);
r(true);
}
};
whatsappPc.addEventListener("iceconnectionstatechange", h);
}),
waitForOutboundAudio(whatsappPc, 12000),
new Promise((r) => setTimeout(r, 12000)),
]);
setTimeout(async () => {
const acceptSuccess = await answerCallToWhatsApp(
callId,
finalWaSdp,
"accept",
activeCalls?.[callId]?.phone_number_id
);
if (acceptSuccess && browserSocket) {
browserSocket.emit("start-browser-timer");
}
}, 10);
} else {
console.error("Pre-accept failed. Aborting accept step.");
}
// Reset session state
browserOfferSdp = null;
whatsappOfferSdp = null;
} catch (error) {
console.error("Error initiating WebRTC bridge:", getAxiosError(error));
}
}
async function waitForOutboundAudio(pc, ms = 12000) {
const start = Date.now();
while (Date.now() - start < ms) {
const stats = await pc.getStats();
for (const r of stats.values()) {
if (
r.type === "outbound-rtp" &&
r.kind === "audio" &&
(r.packetsSent || r.bytesSent)
)
return true;
}
await new Promise((r) => setTimeout(r, 300));
}
return false;
}
Following are the logs from live server
Incoming WhatsApp call from 9180975xxxxx (9180975xxxxx)
Received SDP offer from browser.
Audio track received from browser.
Browser offer SDP set as remote description.
Audio track received from WhatsApp.
WhatsApp offer SDP set as remote description.
MediaStreamTrack {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
addEventListener: [Function: value],
removeEventListener: [Function: value],
uuid: 'c156af26-535c-492d-a2b1-75bcf2859547',
streamId: '50ae6e2f-314a-45f4-9fd1-2b8ce773f552',
remote: true,
label: 'remote audio',
kind: 'audio',
id: 'c0e95fa9-f787-48a3-a31e-8e5f1a26beea',
ssrc: 77909064,
rid: undefined,
header: undefined,
codec: RTCRtpCodecParameters {
payloadType: 111,
mimeType: 'audio/opus',
clockRate: 48000,
channels: 2,
rtcpFeedback: [ [RTCRtcpFeedback] ],
parameters: 'minptime=10;useinbandfec=1',
direction: 'all'
},
enabled: true,
onReceiveRtp: Event {
event: { stack: [Array], promiseStack: [], eventId: 1 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
onReceiveRtcp: Event {
event: { stack: [], promiseStack: [], eventId: 0 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
onSourceChanged: Event {
event: { stack: [], promiseStack: [], eventId: 0 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
stopped: false,
muted: true,
stop: [Function: value],
writeRtp: [Function: value],
Symbol(shapeMode): false,
Symbol(kCapture): false
} <<<<<<<<<<<<<<<< sending track to whatsapp
Forwarded browser audio to WhatsApp.
MediaStreamTrack {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
addEventListener: [Function: value],
removeEventListener: [Function: value],
uuid: '58d00710-efb0-46d8-826c-2d6bdc94e0e2',
streamId: undefined,
remote: true,
label: 'remote audio',
kind: 'audio',
id: '23ce1f0e-c369-41c0-8086-bdc092f1daa6',
ssrc: 2795528785,
rid: undefined,
header: undefined,
codec: RTCRtpCodecParameters {
payloadType: 111,
mimeType: 'audio/opus',
clockRate: 48000,
channels: 2,
rtcpFeedback: [ [RTCRtcpFeedback] ],
parameters: 'maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1',
direction: 'all'
},
enabled: true,
onReceiveRtp: Event {
event: { stack: [Array], promiseStack: [], eventId: 1 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
onReceiveRtcp: Event {
event: { stack: [], promiseStack: [], eventId: 0 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
onSourceChanged: Event {
event: { stack: [], promiseStack: [], eventId: 0 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
stopped: false,
muted: true,
stop: [Function: value],
writeRtp: [Function: value],
Symbol(shapeMode): false,
Symbol(kCapture): false
} <<<<<<<<<<<<<<<< sending track to browser
Received browser-candidate from browser. {
candidate: 'candidate:1995127518 1 udp 2122260223 192.168.1.17 62065 typ host generation 0 ufrag PKLr network-id 1 network-cost 10',
sdpMid: '0',
sdpMLineIndex: 0,
usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Received browser-candidate from browser. {
candidate: 'candidate:884647390 1 udp 41885695 172.237.33.131 41118 typ relay raddr 116.72.105.227 rport 62065 generation 0 ufrag PKLr network-id 1 network-cost 10',
sdpMid: '0',
sdpMLineIndex: 0,
usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Received browser-candidate from browser. {
candidate: 'candidate:136632390 1 tcp 1518280447 192.168.1.17 9 typ host tcptype active generation 0 ufrag PKLr network-id 1 network-cost 10',
sdpMid: '0',
sdpMLineIndex: 0,
usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Browser answer SDP created and sent.
Received browser-candidate from browser. {
candidate: 'candidate:907102327 1 udp 1686052607 116.72.105.227 62065 typ srflx raddr 192.168.1.17 rport 62065 generation 0 ufrag PKLr network-id 1 network-cost 10',
sdpMid: '0',
sdpMLineIndex: 0,
usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
WhatsApp answer SDP prepared.
WhatsApp API Pre-accept Request Payload: {
url: 'https://graph.facebook.com/v21.0/115017851530658/calls',
method: 'POST',
data: {
messaging_product: 'whatsapp',
call_id: 'wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=',
action: 'pre_accept',
session: {
sdp_type: 'answer',
sdp: 'v=0rn' +
'o=- 59754882 0 IN IP4 0.0.0.0rn' +
's=-rn' +
't=0 0rn' +
'a=group:BUNDLE audiorn' +
'a=extmap-allow-mixedrn' +
'a=msid-semantic:WMS *rn' +
'm=audio 9 UDP/TLS/RTP/SAVPF 111rn' +
'c=IN IP4 0.0.0.0rn' +
'a=ice-ufrag:1ba9rn' +
'a=ice-pwd:1b204f1058a8ccc5068917rn' +
'a=ice-options:tricklern' +
'a=fingerprint:sha-256 18:21:C7:E5:37:E6:AE:D3:DE:C5:DE:08:55:9D:13:CE:F8:46:AE:0F:54:18:84:00:A6:5C:60:FE:DE:C1:8D:A6rn' +
'a=setup:activern' +
'a=sendrecvrn' +
'a=mid:audiorn' +
'a=msid:7e5d7d63-467d-4bd2-b41c-8d08d08b1220 23ce1f0e-c369-41c0-8086-bdc092f1daa6rn' +
'a=rtcp:9 IN IP4 0.0.0.0rn' +
'a=rtcp-muxrn' +
'a=ssrc:4129580503 cname:c6837d9e-0285-4fb2-81ac-f684d95751a9rn' +
'a=rtpmap:111 opus/48000/2rn' +
'a=rtcp-fb:111 transport-ccrn' +
'a=fmtp:111 maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1rn'
}
}
}
Pre-accept API Response: { messaging_product: 'whatsapp', success: true }
WhatsApp API Pre-accept Request Payload: {
url: 'https://graph.facebook.com/v21.0/115017851530658/calls',
method: 'POST',
data: {
messaging_product: 'whatsapp',
call_id: 'wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=',
action: 'accept',
session: {
sdp_type: 'answer',
sdp: 'v=0rn' +
'o=- 59754882 0 IN IP4 0.0.0.0rn' +
's=-rn' +
't=0 0rn' +
'a=group:BUNDLE audiorn' +
'a=extmap-allow-mixedrn' +
'a=msid-semantic:WMS *rn' +
'm=audio 9 UDP/TLS/RTP/SAVPF 111rn' +
'c=IN IP4 0.0.0.0rn' +
'a=ice-ufrag:1ba9rn' +
'a=ice-pwd:1b204f1058a8ccc5068917rn' +
'a=ice-options:tricklern' +
'a=fingerprint:sha-256 18:21:C7:E5:37:E6:AE:D3:DE:C5:DE:08:55:9D:13:CE:F8:46:AE:0F:54:18:84:00:A6:5C:60:FE:DE:C1:8D:A6rn' +
'a=setup:activern' +
'a=sendrecvrn' +
'a=mid:audiorn' +
'a=msid:7e5d7d63-467d-4bd2-b41c-8d08d08b1220 23ce1f0e-c369-41c0-8086-bdc092f1daa6rn' +
'a=rtcp:9 IN IP4 0.0.0.0rn' +
'a=rtcp-muxrn' +
'a=ssrc:4129580503 cname:c6837d9e-0285-4fb2-81ac-f684d95751a9rn' +
'a=rtpmap:111 opus/48000/2rn' +
'a=rtcp-fb:111 transport-ccrn' +
'a=fmtp:111 maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1rn'
}
}
}
Pre-accept API Response: { messaging_product: 'whatsapp', success: true }
Following are the logs i’m getting on local
Incoming WhatsApp call from 91809xxxxxxx (91809xxxxxxx)
Received SDP offer from browser.
Audio track received from browser.
Browser offer SDP set as remote description.
Audio track received from WhatsApp.
WhatsApp offer SDP set as remote description.
MediaStreamTrack {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
addEventListener: [Function: value],
removeEventListener: [Function: value],
uuid: 'c156af26-535c-492d-a2b1-75bcf2859547',
streamId: '50ae6e2f-314a-45f4-9fd1-2b8ce773f552',
remote: true,
label: 'remote audio',
kind: 'audio',
id: 'c0e95fa9-f787-48a3-a31e-8e5f1a26beea',
ssrc: 77909064,
rid: undefined,
header: undefined,
codec: RTCRtpCodecParameters {
payloadType: 111,
mimeType: 'audio/opus',
clockRate: 48000,
channels: 2,
rtcpFeedback: [ [RTCRtcpFeedback] ],
parameters: 'minptime=10;useinbandfec=1',
direction: 'all'
},
enabled: true,
onReceiveRtp: Event {
event: { stack: [Array], promiseStack: [], eventId: 1 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
onReceiveRtcp: Event {
event: { stack: [], promiseStack: [], eventId: 0 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
onSourceChanged: Event {
event: { stack: [], promiseStack: [], eventId: 0 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
stopped: false,
muted: true,
stop: [Function: value],
writeRtp: [Function: value],
Symbol(shapeMode): false,
Symbol(kCapture): false
} <<<<<<<<<<<<<<<< sending track to whatsapp
Forwarded browser audio to WhatsApp.
MediaStreamTrack {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
addEventListener: [Function: value],
removeEventListener: [Function: value],
uuid: '58d00710-efb0-46d8-826c-2d6bdc94e0e2',
streamId: undefined,
remote: true,
label: 'remote audio',
kind: 'audio',
id: '23ce1f0e-c369-41c0-8086-bdc092f1daa6',
ssrc: 2795528785,
rid: undefined,
header: undefined,
codec: RTCRtpCodecParameters {
payloadType: 111,
mimeType: 'audio/opus',
clockRate: 48000,
channels: 2,
rtcpFeedback: [ [RTCRtcpFeedback] ],
parameters: 'maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1',
direction: 'all'
},
enabled: true,
onReceiveRtp: Event {
event: { stack: [Array], promiseStack: [], eventId: 1 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
onReceiveRtcp: Event {
event: { stack: [], promiseStack: [], eventId: 0 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
onSourceChanged: Event {
event: { stack: [], promiseStack: [], eventId: 0 },
ended: false,
onended: undefined,
onerror: [Function: value],
execute: [Function: value],
complete: [Function: value],
error: [Function: value],
allUnsubscribe: [Function: value],
subscribe: [Function: value],
queuingSubscribe: [Function: value],
once: [Function: value],
watch: [Function: value],
asPromise: [Function: value]
},
stopped: false,
muted: true,
stop: [Function: value],
writeRtp: [Function: value],
Symbol(shapeMode): false,
Symbol(kCapture): false
} <<<<<<<<<<<<<<<< sending track to browser
Received browser-candidate from browser. {
candidate: 'candidate:1995127518 1 udp 2122260223 192.168.1.17 62065 typ host generation 0 ufrag PKLr network-id 1 network-cost 10',
sdpMid: '0',
sdpMLineIndex: 0,
usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Received browser-candidate from browser. {
candidate: 'candidate:884647390 1 udp 41885695 172.237.33.131 41118 typ relay raddr 116.72.105.227 rport 62065 generation 0 ufrag PKLr network-id 1 network-cost 10',
sdpMid: '0',
sdpMLineIndex: 0,
usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Received browser-candidate from browser. {
candidate: 'candidate:136632390 1 tcp 1518280447 192.168.1.17 9 typ host tcptype active generation 0 ufrag PKLr network-id 1 network-cost 10',
sdpMid: '0',
sdpMLineIndex: 0,
usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Browser answer SDP created and sent.
Received browser-candidate from browser. {
candidate: 'candidate:907102327 1 udp 1686052607 116.72.105.227 62065 typ srflx raddr 192.168.1.17 rport 62065 generation 0 ufrag PKLr network-id 1 network-cost 10',
sdpMid: '0',
sdpMLineIndex: 0,
usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
WhatsApp answer SDP prepared.
WhatsApp API Pre-accept Request Payload: {
url: 'https://graph.facebook.com/v21.0/115017851530658/calls',
method: 'POST',
data: {
messaging_product: 'whatsapp',
call_id: 'wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=',
action: 'pre_accept',
session: {
sdp_type: 'answer',
sdp: 'v=0rn' +
'o=- 59754882 0 IN IP4 0.0.0.0rn' +
's=-rn' +
't=0 0rn' +
'a=group:BUNDLE audiorn' +
'a=extmap-allow-mixedrn' +
'a=msid-semantic:WMS *rn' +
'm=audio 9 UDP/TLS/RTP/SAVPF 111rn' +
'c=IN IP4 0.0.0.0rn' +
'a=ice-ufrag:1ba9rn' +
'a=ice-pwd:1b204f1058a8ccc5068917rn' +
'a=ice-options:tricklern' +
'a=fingerprint:sha-256 18:21:C7:E5:37:E6:AE:D3:DE:C5:DE:08:55:9D:13:CE:F8:46:AE:0F:54:18:84:00:A6:5C:60:FE:DE:C1:8D:A6rn' +
'a=setup:activern' +
'a=sendrecvrn' +
'a=mid:audiorn' +
'a=msid:7e5d7d63-467d-4bd2-b41c-8d08d08b1220 23ce1f0e-c369-41c0-8086-bdc092f1daa6rn' +
'a=rtcp:9 IN IP4 0.0.0.0rn' +
'a=rtcp-muxrn' +
'a=ssrc:4129580503 cname:c6837d9e-0285-4fb2-81ac-f684d95751a9rn' +
'a=rtpmap:111 opus/48000/2rn' +
'a=rtcp-fb:111 transport-ccrn' +
'a=fmtp:111 maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1rn'
}
}
}
Pre-accept API Response: { messaging_product: 'whatsapp', success: true }
WhatsApp API Pre-accept Request Payload: {
url: 'https://graph.facebook.com/v21.0/115017851530658/calls',
method: 'POST',
data: {
messaging_product: 'whatsapp',
call_id: 'wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=',
action: 'accept',
session: {
sdp_type: 'answer',
sdp: 'v=0rn' +
'o=- 59754882 0 IN IP4 0.0.0.0rn' +
's=-rn' +
't=0 0rn' +
'a=group:BUNDLE audiorn' +
'a=extmap-allow-mixedrn' +
'a=msid-semantic:WMS *rn' +
'm=audio 9 UDP/TLS/RTP/SAVPF 111rn' +
'c=IN IP4 0.0.0.0rn' +
'a=ice-ufrag:1ba9rn' +
'a=ice-pwd:1b204f1058a8ccc5068917rn' +
'a=ice-options:tricklern' +
'a=fingerprint:sha-256 18:21:C7:E5:37:E6:AE:D3:DE:C5:DE:08:55:9D:13:CE:F8:46:AE:0F:54:18:84:00:A6:5C:60:FE:DE:C1:8D:A6rn' +
'a=setup:activern' +
'a=sendrecvrn' +
'a=mid:audiorn' +
'a=msid:7e5d7d63-467d-4bd2-b41c-8d08d08b1220 23ce1f0e-c369-41c0-8086-bdc092f1daa6rn' +
'a=rtcp:9 IN IP4 0.0.0.0rn' +
'a=rtcp-muxrn' +
'a=ssrc:4129580503 cname:c6837d9e-0285-4fb2-81ac-f684d95751a9rn' +
'a=rtpmap:111 opus/48000/2rn' +
'a=rtcp-fb:111 transport-ccrn' +
'a=fmtp:111 maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1rn'
}
}
}
Pre-accept API Response: { messaging_product: 'whatsapp', success: true }