在我的多对等 webrtc 客户端(在 chrome 上测试)中,成功建立了稳定的连接,但是在我收到被调用者的回答后,ontrack事件没有触发,因此流 sourceObj 没有附加到我的 DOM。为什么?被调用者显示两个视频(本地和远程),但在调用者端未添加远程视频,这似乎是由于ontrack 事件未触发。
我在发送 Offer/Answer 之前创建了所有 RTCPeerConnection,并在我将 ontrack 事件绑定到它之后,在创建时将本地 Tracks 添加到它。然后我发送报价/答案并遵循信令流程。
class WebRTC_Client {
private serversCfg = {
iceServers: [{
urls: ["stun:stun.l.google.com:19302"]
}]
};
...
private gotStream(stream) {
window.localStream = stream;
...
}
private stopLocalTracks(){
if (window.localStream) {
window.localStream.getTracks().forEach(function (track) {
track.stop();
});
var videoTracks = window.localStream.getVideoTracks();
for (var i = 0; i !== videoTracks.length; ++i) {
videoTracks[i].stop();
}
}
}
private start() {
var self = this;
...
this.stopLocalTracks();
...
navigator.mediaDevices.getUserMedia(this.getConstrains())
.then((stream) => {
self.gotStream(stream);
trace('Send signal to peers that I am ready to be called: onReadyForTeamspeak');
self.SignalingChannel.send(JSON.stringify({type: 'onReadyForTeamspeak'}));
})
.catch( self.errorHandler );
}
public addPeerId(peerId){
this.availablePeerIds[peerId] = peerId;
this.preparePeerConnection(peerId);
}
private preparePeerConnection(peerId){
var self = this;
if( this.peerConns[peerId] ){
return;
}
this.peerConns[peerId] = new RTCPeerConnection(this.serversCfg);
this.peerConns[peerId].ontrack = function (evt) { self.gotRemoteStream(evt, peerId); };
this.peerConns[peerId].onicecandidate = function (evt) { self.iceCallback(evt, peerId); };
this.addTracks(peerId);
}
private addTracks(peerId){
var self = this;
var localTracksCount = 0;
window.localStream.getTracks().forEach(
function (track) {
self.peerConns[peerId].addTrack(
track,
window.localStream
);
}
);
}
private call() {
var self = this;
for( let peerId in this.availablePeerIds ){
if( !this.availablePeerIds.hasOwnProperty(peerId) ){
continue;
}
if( this.isCaller(peerId) ) {
this.preparePeerConnection(peerId);
this.createOffer(peerId);
}
}
}
private createOffer(peerId){
var self = this;
this.peerConns[peerId].createOffer( this.offerOptions )
.then( function (offer) { return self.peerConns[peerId].setLocalDescription(offer); } )
.then( function () {
self.SignalingChannel.send(JSON.stringify({ "sdp": self.peerConns[peerId].localDescription, "remotePeerId": peerId, "type": "onWebRTCPeerConn" }));
})
.catch( this.errorHandler );
}
private answerCall(peerId){
var self = this;
this.peerConns[peerId].createAnswer()
.then( function (answer) { return self.peerConns[peerId].setLocalDescription(answer); } )
.then( function () {
self.SignalingChannel.send(JSON.stringify({ "sdp": self.peerConns[peerId].localDescription, "remotePeerId": peerId, "type": "onWebRTCPeerConn" }));
})
.catch( this.errorHandler );
}
...
private gotRemoteStream(e, peerId) {
if (!this.videoBillboards[peerId]) {
this.createMediaElements(peerId);
}
if (this.videoAssets[peerId].srcObject !== e.streams[0]) {
this.videoAssets[peerId].srcObject = e.streams[0];
}
}
private iceCallback(event, peerId) {
this.SignalingChannel.send(JSON.stringify({ "candidate": event.candidate, "remotePeerId": peerId, "type": "onWebRTCPeerConn" }));
}
private handleCandidate(candidate, peerId) {
this.peerConns[peerId].addIceCandidate(candidate)
.then(
this.onAddIceCandidateSuccess,
this.onAddIceCandidateError
);
}
...
private handleSignals(signal){
var self = this,
peerId = signal.connectionId;
this.addPeerId(peerId);
if( signal.sdp ) {
var desc = new RTCSessionDescription(signal.sdp);
this.peerConns[peerId].setRemoteDescription(desc)
.then(function () {
if (desc.type === 'offer') {
self.answerCall(peerId);
}
})
.catch( this.errorHandler );
} else if( signal.candidate ){
this.handleCandidate(new RTCIceCandidate(signal.candidate), peerId);
} else if( signal.closeConn ){
this.endCall(peerId,true);
}
}
}