我已经构建了一个 vuejs 超级基础的一对一 webRTC 视频聊天。我将 PubNub 用于信令,将 Xirsys 用于 ICE。
但是我在“通话”中收到此错误。但是页面加载正常。
错误 InvalidStateError:无法设置远程报价 sdp:在错误状态下调用:kHaveLocalOffer
<template>
<div>
<video ref="localVideo" id="localVideo" autoplay playsinline></video>
<br />
<video ref="remoteVideo" id="remoteVideo" autoplay playsinline></video>
<br />
<button type="button" class="btn btn-light btn-lg btn-block" @click="callClick">Call</button>
</div>
</template>
<script>
export default {
data() {
return {
localVideo: {type: Object},
remoteVideo: {type: Object},
iceServers: [],
myPeerConnection: {type: Object},
channelName: ['testtesttest'],
mediaConstraintsLocal: {
video: {
width: { min: 640, ideal: 640 },
height: { min: 480, ideal: 480 },
aspectRatio: { ideal: 1.7777777778 },
frameRate: { min: 10, ideal: 30},
facingMode: { ideal: 'user' }
},
audio: {
sampleSize: 16,
channelCount: 2,
volume: 0
}
},
mediaConstraintsRemote: {
video: {
width: { min: 640, ideal: 640 },
height: { min: 480, ideal: 480 },
aspectRatio: { ideal: 1.7777777778 },
frameRate: { min: 10, ideal: 30},
facingMode: { ideal: 'user' }
},
audio: {
sampleSize: 16,
channelCount: 2,
volume: 0
}
},
};
},
mounted() {
var _this = this;
// LOAD PUBNUB
this.pubnub.load();
// SUBSCRIBE TO PUBNUB CHANNEL
this.$pubnub.subscribe({
channels: this.channelName
});
// REGISTER VIDEO DISPLAYS
_this.localVideo = _this.$refs.localVideo;
_this.remoteVideo = _this.$refs.remoteVideo;
// GET PEER CONNECTION AND XIRSYS ICE SERVERS
this.createPeerConnection();
// GET USER MEDIA SET CONSTRAINTS AND STREAM
navigator.mediaDevices.getUserMedia(this.mediaConstraintsLocal)
.then(stream => {
window.stream = stream;
this.localVideo.srcObject = stream;
this.localVideo.play();
})
.catch(function(errors) {
console.log('%c Errors ' + errors, 'background: #222; color: #bada55');
});
// REGISTER PUBNUB LISTENER
_this.$pubnub.addListener({
// PUBNUB ON MESSAGE
message: function(message) {
// PUBNUB LISTENING CHANNEL
this.channelName = message.channel;
// ICE OFFER
if (message.ice) {
_this.myPeerConnection.addIceCandidate(new RTCIceCandidate(message.ice))
.catch(function(errors) {
console.log('%c Errors ' + errors, 'background: #222; color: #bada55');
});
}
// SDP OFFER
if (message.message.type == 'offer') {
console.log(message.message.type + ' ON ' + message.channel);
console.log('SDP OFFER ' + _this.myPeerConnection.signalingState);
_this.myPeerConnection.setRemoteDescription(new RTCSessionDescription(message.message))
.then(function() {
return navigator.mediaDevices.getUserMedia(_this.mediaConstraintsRemote);
})
// GET VIDEO ADD VIDEO OBJECT
.then(function(stream) {
_this.remoteVideo.srcObject = stream;
_this.remoteVideo.play();
return _this.myPeerConnection.addStream(stream);
})
// PUBLISH ANSWER
.then(function() {
_this.myPeerConnection.createAnswer()
.then(function(answer) {
return _this.myPeerConnection.setLocalDescription(answer);
})
.then(function() {
// PUBNUB PUBLISH LOCAL DESCRIPTION AS ANSWER
console.log('PUBNUB PUBLISH LOCAL DESCRIPTION AS ANSWER ' + _this.myPeerConnection.signalingState);
_this.$pubnub.publish({
message: _this.myPeerConnection.localDescription,
channel: _this.channelName
});
});
})
.catch(function(errors) {
console.log('%c Errors ' + errors, 'background: #222; color: #bada55');
});
}
// // SDP ANSWER
if (message.message.type == 'answer') {
console.log(message.message.type + ' ON ' + message.channel);
console.log('SDP ANSWER ' + _this.myPeerConnection.signalingState);
_this.myPeerConnection.setRemoteDescription(new RTCSessionDescription(message.message))
.then(function() {
console.log('SET REMOTE DESCRIPTION ' + _this.myPeerConnection.signalingState);
return navigator.mediaDevices.getUserMedia(_this.mediaConstraintsRemote);
})
// ADD VIDEO OBJECT
.then(function(stream) {
_this.remoteVideo.srcObject = stream;
_this.remoteVideo.play();
return _this.myPeerConnection.addStream(stream);
})
.catch(function(errors) {
console.log('%c Errors ' + errors, 'background: #222; color: #bada55');
});
}
}
});
},
methods: {
callClick() {
console.log('call');
var _this = this;
// GET PEER CONNECTION AND XIRSYS ICE SERVERS
this.createPeerConnection();
// myPeerConnection
console.log('this.myPeerConnection ' + this.myPeerConnection);
// CREATE OFFER
console.log('CREATE OFFER ' + this.myPeerConnection.signalingState);
// ADD MEDIA TRACKS
stream.getTracks().forEach(track => this.myPeerConnection.addTrack(track, stream));
this.myPeerConnection.createOffer()
.then(function(offer) {
console.log('SET LOCAL DESCRIPTION ' + _this.myPeerConnection.signalingState);
return _this.myPeerConnection.setLocalDescription(offer);
})
// PUBLISH OFFER
.then(function() {
// PUBNUB PUBLISH LOCAL DESCRIPTION AS OFFER
console.log('PUBNUB PUBLISH LOCAL DESCRIPTION AS OFFER ' + _this.myPeerConnection.signalingState);
_this.$pubnub.publish({
message: _this.myPeerConnection.localDescription,
channel: _this.channelName
});
})
.catch(function(errors) {
console.log('%c Errors ' + errors, 'background: #222; color: #bada55');
});
},
createPeerConnection() {
// GET XIRSYS ICE SERVERS
Vue.http.options.root = '/root';
Vue.http.headers.common['Authorization'] = 'Basic ' + btoa('ive:648');
this.$http.put('https://global.xirsys.net/_turn/Default/')
.then(response => (this.iceServers = response.data.v))
.then(function() {
console.log('ICE SERVERS ' + this.iceServers);
this.myPeerConnection = new RTCPeerConnection(this.iceServers);
})
.catch(function(errors) {
console.log('%c Errors ' + errors, 'background: #222; color: #bada55');
});
}
}
}
</script>
任何帮助将不胜感激。