I've been tasked with creating an audio chat room for 2 users.
Initially, I used the following app example: Peer connection: audio only
After converting the code to TypeScript, it successfully ran:
However, I'm facing challenges getting it to work between two users (not in one tab; I open 2 Firefox windows). My knowledge of Angular is quite basic. Although not an Angular developer by profession (I typically work on desktop apps), I am venturing into Angular development for this specific project.
The objective is to send an offer event to a communication platform (to connect with another user within the same room - always 2 users per room). The event requires a type field set to offer
and includes sdp
.
The other user responds with an answer event within the same platform and room. This response also includes sdp
, with its type set to answer
.
We are utilizing matrix.org. For detailed VOIP specifications, refer to VOIP specs
Although I have successfully implemented sending these events to the communication platform and reading events from the room, I'm stuck at making the functionality fully operational.
I've dedicated time over weekends trying to troubleshoot the issues, yet setbacks like
DOMException: "Cannot set remote answer in state stable"
continue to persist.
I don't expect a complete working code solution (I understand it's a task that may span several days), but any insights or advice to make the implementation smoother and feasible for someone with minimal Angular and webRTC expertise would be highly valued.
Interestingly, the Stackblitz example doesn't seem to function properly in Chrome for me, although it runs smoothly in Firefox.
//EDIT
I'm currently exploring a new approach like the one below:
placeCall() {
this.turnServer();
this.uuid = this.createUuid();
this.initCall();
}
initCall(){
this.pc1 = new RTCPeerConnection(PEER_CONNECTION_CONFIG);
navigator.mediaDevices
.getUserMedia({
audio: true,
video: false
})
.then(stream => this.gotStreamSetOffer(stream))
.catch(e => {
console.log('error');
alert(`getUserMedia() error: ${e.name}`);
});
}
gotStreamSetOffer(stream) {
this.hangupButton.nativeElement.disabled = false;
this.localStream = stream;
let audioTracks = this.localStream.getAudioTracks();
console.log(audioTracks);
if (audioTracks.length > 0) {
console.log(`Using Audio device: ${audioTracks[0].label}`);
}
this.localStream.getTracks().forEach(track => this.pc1.addTrack(track, this.localStream));
this.pc1.createOffer(this.offerOptions)
.then(v => {
this.pc1.setLocalDescription(v);
this.sdp = v.sdp;
this.localOfferSDP = v;
this.messageService.callInvite(JSON.stringify(new CallInviteModel(this.uuid, 0, 30000, new OfferModel("offer", v.sdp))), this.roomId)
.subscribe(res => {
this.candidates();
});
});
this.pc1.onicecandidate = e => {
if (e.candidate) return;
};
// Wait for answer in room and save answer to v
this.hangupButton.nativeElement.disabled = false;
this.callId = v.content.call_id;
this.remoteOfferSDP = v.content.answer;
this.pc1.setRemoteDescription(new RTCSessionDescription(this.remoteOfferSDP));
}
answer() {
this.pc1 = new RTCPeerConnection(PEER_CONNECTION_CONFIG);
let answer = new AnswerModel("answer", this.localOfferSDP.sdp);
let callAnswer = new CallAnswerModel(this.callId, 0, answer);
let json = JSON.stringify(callAnswer);
this.messageService.callAnswer(json, this.roomId)
.subscribe(res => {
});
this.remoteOfferSDP = this.localOfferSDP;
this.remoteOfferSDP.type = 'answer';
this.pc1.setRemoteDescription(new RTCSessionDescription(this.localOfferSDP))
.then((a) => this.pc1.createAnswer())
.then(d => {
this.pc1.setLocalDescription(this.remoteOfferSDP)
}).catch(e => console.log(e));
this.pc1.onicecandidate = e => {
if (e.candidate) return;
};
}
Despite these efforts, I encountered a recurrence of the error:
DOMException: "Cannot set remote answer in state stable"
//EDIT2 Recently, another exception surfaced:
DOMException: "Answer contains illegal setup attribute "actpass" at level 0"
. The presence of actpass
in the sdp
is auto-generated and leads to this particular issue when using Firefox.