我尝试使用webrtc
技术react.js
和meteor.js
进行简单的聊天。
这是客户端代码:
class Rtc extends Component {
constructor(props) {
super(props);
}
componentDidUpdate(){
let localVideo, remoteVideo, peerConnection, localStream;
$('#start').on('click', ()=>{ start(true) });
let id = Meteor.uuid();
localVideo = document.getElementById('localVideo');
remoteVideo = document.getElementById('remoteVideo');
if (!this.props.loadingRtc) {
this.props.messagesRtc.forEach((item, i ,arr)=>{
let signal = JSON.parse(item.text);
if(i == 0)return;
gotMessageFromServer(signal);
});
}
if(navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia( { video:true, audio:true}).then( ( stream )=> {
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream);
}).catch(errorHandler);
} else { alert('Your browser does not support getUserMedia API'); }
function start(isCaller) {
peerConnection = new RTCPeerConnection( { 'iceServers': [{'urls': 'stun:stun.services.mozilla.com'}, {'urls': 'stun:stun.l.google.com:19302'},]});
peerConnection.onicecandidate = ( e ) => {
console.log('e.candidate', e.candidate);
if(e.candidate != null) {
Meteor.call('addMsgRtc', JSON.stringify({'ice': e.candidate, '_id':id}), id);
}
};
peerConnection.onaddstream = ( e )=>{
remoteVideo.src = window.URL.createObjectURL(e.stream);
};
peerConnection.addStream(localStream);
if(isCaller) {
peerConnection.createOffer().then(createdDescription).catch(errorHandler);
}
}
function gotMessageFromServer(signal) {
if(!peerConnection) start(false);
if(signal._id == id) return;
if(signal.sdp) {
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(()=> {
if(signal.sdp.type == 'offer') {
peerConnection.createAnswer().then(createdDescription).catch(errorHandler);
}
}).catch(errorHandler);
} else if(signal.ice) {
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice)).catch(errorHandler);
}
}
function createdDescription(description) {
peerConnection.setLocalDescription(description).then(()=> {
Meteor.call('addMsgRtc', JSON.stringify({'sdp':peerConnection.localDescription, '_id':id}), id);
}).catch(errorHandler);
}
function errorHandler(error) { console.log(error); }
}
render() {
return (
<div>
<video id="localVideo" autoPlay muted style={{width:"40%"}}></video>
<video id="remoteVideo" autoPlay style={{width:"40%"}}></video>
<br/>
<input type="button" id="start" value="Start Video"/>
</div>
);
}
}
export default createContainer( ()=> {
const subscriptionRtc = Meteor.subscribe('rtc');
const loadingRtc = !subscriptionRtc.ready();
return {
loadingRtc:loadingRtc,
messagesRtc: msgRtc.find().fetch(),
};
}, App);
服务器代码:
export const msgRtc = new Mongo.Collection('rtc');
let messagesRtc = [];
let clients = [];
Meteor.publish('rtc', function wsPub() {
clients.push(this);
_.each(messagesRtc, (message) => {
this.added('rtc', message._id, message);
});
this.ready();
});
Meteor.methods({
'addMsgRtc'(arr, id) {
let newMessage = {_id:id, 'text':arr};
messagesRtc.push(newMessage);
_.each(clients, (client) => {
client.added('rtc', id, newMessage);
});
},
问题在于,为什么在getUserMedia
初始化之后不希望进一步推广这些视频,哪些不是我无法理解的。因为它实际上是与通常的websockets
like this相似的代码,并且同步很好。
UPD:
单击按钮并调用函数start
时。
TypeError:RTCPeerConnection.addStream的参数1不是对象
如果要放入websockets
,则会发现另一个错误:
代码:
navigator.mediaDevices.getUserMedia( { video:true, audio:true}).then( ( stream )=> {
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream);
}).catch(errorHandler).then(()=>{
if (!this.props.loadingRtc) {
for(let i of this.props.messagesRtc){
let signal = JSON.parse(i.text);
gotMessageFromServer(signal)
}
}
}).catch(errorHandler);
错误:
DOMException [InvalidStateError:&#34;无法设置远程报价或答案 目前的州有远程提供&#34;代码:11 nsresult:0x8053000b] app.js:11075:9 DOMException [InvalidStateError:&#34;没有未完成的优惠&#34; 代码:11 nsresult:0x8053000b]