I’m building a web-based SIP phone application using JsSIP (version 3.10.0) to handle VoIP calls over WebRTC. My setup works fine for inbound calls—audio streams both ways—but I’m facing an issue with outbound calls where I can’t hear the remote party, and the "peerconnection" event isn’t firing as expected.
What I’m Doing
Setup: I’m using JsSIP to connect to a SIP server via WebSocket (WSS). The client registers successfully and can initiate/receive calls. Code Structure: I handle all new sessions (inbound and outbound) in a handleNewRTCSession function triggered by the "newRTCSession" event from JsSIP’s UA. For WebRTC, I rely on the "peerconnection" event to access the RTCPeerConnection and attach a "track" listener to capture the remote audio stream. Outbound Call Flow: I call userAgent.call(target, callOptions) to start an outbound call. The call connects (remote party answers), and they can hear me, but I don’t hear them.
const userAgent = new JsSIP.UA({
uri: "sip:user@example.com",
password: "****",
sockets: [new JsSIP.WebSocketInterface("wss://sip-server.example.com:7443")],
});
const callOptions = {
mediaConstraints: { audio: true, video: false },
pcConfig: { iceServers: [{ urls: "stun:stun.l.google.com:19302" }] },
};
userAgent.on("newRTCSession", handleNewRTCSession);
function handleNewRTCSession(e) {
const session = e.session;
console.log("New session:", session.direction);
session.on("peerconnection", (data) => {
console.log("Peerconnection event:", data);
const peerConnection = data.peerconnection;
peerConnection.addEventListener("track", (event) => {
console.log("Remote stream received:", event.streams[0]);
document.getElementById("remoteAudio").srcObject = event.streams[0];
});
});
session.on("accepted", () => {
console.log("Call accepted");
});
session.on("failed", (e) => {
console.log("Call failed:", e.cause);
});
if (session.direction === "outgoing") {
console.log("Outbound call started");
}
}
function makeCall(target) {
userAgent.call(target, callOptions);
}
// Start UA
userAgent.start();
The Workaround which i'm trying right now is forcing peerconnection when the call is accepted in outbound case:
if (session.connection && session.direction === óutgoing) {
console.log("Manually handling peer connection:", session.connection);
handlePeerConnection({ peerconnection: session.connection });
}
function handlePeerConnection(data) {
console.log(data);
const peerConnection = data.peerconnection;
peerConnection.addEventListener("track", (event) => {
console.log(event);
console.log("StreamViewType", event.streams);
const remoteStream = event.streams[0];
console.log("Remote stream received:", remoteStream);
audioElement.srcObject = remoteStream;
audioElement
.play()
.catch((e) => console.error("Audio playback failed:", e));
});
peerConnection.addEventListener("icecandidate", (event) => {
if (event.candidate) {
console.log("ICE candidate:", event.candidate);
} else {
console.log("ICE gathering complete");
}
});
}
Questions
Additional Details
JsSIP Version: 3.10.0
Browser: Chrome (latest)
SIP Server: A hosted FusionPBX.
SDP: Local offers Opus/G722/PCMU, remote responds with G722, both sendrecv.
I’d appreciate any insights or suggestions to fix this cleanly without relying on the workaround. Thanks!
My approach is to
// modify your function makeCall(target)
function makeCall(target) {
outgoingSession = userAgent.call(target, callOptions);
setupMedia(outgoingSession);
}
and then implement
session.connection.addEventListener('track', ({ track, streams: [stream] }) => {
// logic identical to your peerConnection.addEventListener("track", (event) => {});
});
within setupMedia.
The specific reason, I suspect, is that addEventListener only captures newly added tracks. In your method, during outgoing calls, the audio may not be considered newly added?