Reactjs WebRTC反应流多轨道问题。摄像机&x2B;屏幕共享
我正在一个新网站上工作。您可以加入房间通话并拨打语音电话,因此可以使用网络摄像头,但也可以共享屏幕 问题是,当我将曲目添加到流中时,对等方无法正常工作。。。我不知道怎么解决这个问题。我还尝试将代码从添加曲目更改为添加新流或其他任何内容,但找不到解决方案。有人能帮我吗 客户:Reactjs WebRTC反应流多轨道问题。摄像机&x2B;屏幕共享,reactjs,webrtc,Reactjs,Webrtc,我正在一个新网站上工作。您可以加入房间通话并拨打语音电话,因此可以使用网络摄像头,但也可以共享屏幕 问题是,当我将曲目添加到流中时,对等方无法正常工作。。。我不知道怎么解决这个问题。我还尝试将代码从添加曲目更改为添加新流或其他任何内容,但找不到解决方案。有人能帮我吗 客户: export default function Meeting(props) { const userVideo = useRef(); const partnerVideo = useRef(); const screen
export default function Meeting(props) {
const userVideo = useRef();
const partnerVideo = useRef();
const screenShare = useRef();
const peerRef = useRef();
const socketRef = useRef();
const otherUser = useRef();
const userStream = useRef();
const userScreen = useRef();
useEffect(() => {
navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(stream => {
userVideo.current.srcObject = stream;
userStream.current = stream;
socketRef.current = socketIOClient.connect(ENDPOINT);
socketRef.current.emit("join room", props.room);
socketRef.current.on('other user', userID => {
callUser(userID);
otherUser.current = userID;
});
socketRef.current.on("user joined", userID => {
otherUser.current = userID;
});
socketRef.current.on("offer", handleRecieveCall);
socketRef.current.on("answer", handleAnswer);
socketRef.current.on("ice-candidate", handleNewICECandidateMsg);
});
}, []);
function callUser(userID) {
console.log("call user - - -d-s-d-s-d--sd-sdd-sd-ssd-sd-sd--");
peerRef.current = createPeer(userID);
userStream.current.getTracks().forEach(track => peerRef.current.addTrack(track, userStream.current));
}
function createPeer(userID) {
const peer = new RTCPeerConnection({
//sdpSemantics: 'unified-plan',
iceServers: [
{
urls: "stun:stun.stunprotocol.org"
},
{
urls: 'turn:numb.viagenie.ca',
credential: 'muazkh',
username: 'webrtc@live.com'
},
]
});
peer.onicecandidate = handleICECandidateEvent;
peer.ontrack = handleTrackEvent;
peer.onnegotiationneeded = () => {
if (peer.signalingState != "stable") return;
handleNegotiationNeededEvent(userID);
}
return peer;
}
function handleNegotiationNeededEvent(userID) {
console.log("negotiationsad-das-d-as-d-asd--asd-a-sd-a-sd-");
peerRef.current.createOffer().then(offer => {
return peerRef.current.setLocalDescription(offer);
}).then(() => {
const payload = {
target: userID,
type: "video-offer",
caller: socketRef.current.id,
sdp: peerRef.current.localDescription
};
socketRef.current.emit("offer", payload);
}).catch(e => console.log(e));
}
function handleRecieveCall(incoming) {
peerRef.current = createPeer();
const desc = new RTCSessionDescription(incoming.sdp);
peerRef.current.setRemoteDescription(desc).then(() => {
userStream.current.getTracks().forEach(track => peerRef.current.addTrack(track, userStream.current));
}).then(() => {
return peerRef.current.createAnswer();
}).then(answer => {
return peerRef.current.setLocalDescription(answer);
}).then(() => {
const payload = {
target: incoming.caller,
type: "video-offer",
caller: socketRef.current.id,
sdp: peerRef.current.localDescription
}
socketRef.current.emit("answer", payload);
})
}
function handleAnswer(message) {
const desc = new RTCSessionDescription(message.sdp);
peerRef.current.setRemoteDescription(desc).catch(e => console.log(e));
}
function handleICECandidateEvent(e) {
if (e.candidate) {
const payload = {
target: otherUser.current,
candidate: e.candidate,
}
socketRef.current.emit("ice-candidate", payload);
}
}
function handleNewICECandidateMsg(incoming) {
const candidate = new RTCIceCandidate(incoming);
if (peerRef.current && candidate) {
peerRef.current.addIceCandidate(candidate).catch(e => console.log(e));
}
}
function handleTrackEvent(e) {
var stream = e.streams[0];
var tracks = stream.getTracks();
var lun = tracks.length;
console.log(tracks);
if (lun === 2) {
partnerVideo.current.srcObject = stream;
} else if (lun === 1) {
screenShare.current.srcObject = stream;
}
};
function shareScreen() {
navigator.mediaDevices.getDisplayMedia({ cursor: true }).then(stream => {
screenShare.current.srcObject = stream;
userScreen.current = stream;
const screenTrack = stream.getTracks()[0];
callUser(otherUser.current);
peerRef.current.addTrack(screenTrack, stream);
screenTrack.onended = function () {
peerRef.current.removeTrack(screenTrack);
}
})
}
return (
<div>
<video controls style={{ height: 500, width: 500 }} autoPlay ref={userVideo} />
<video controls style={{ height: 500, width: 500 }} autoPlay ref={partnerVideo} />
<video controls style={{ height: 500, width: 500 }} autoPlay ref={screenShare} />
<button onClick={shareScreen}>Share screen</button>
</div>
);
导出默认功能会议(道具){
const userVideo=useRef();
const partnerVideo=useRef();
const screenShare=useRef();
const peerRef=useRef();
const socketRef=useRef();
const otherUser=useRef();
const userStream=useRef();
const userScreen=useRef();
useffect(()=>{
navigator.mediaDevices.getUserMedia({audio:true,video:true})。然后(stream=>{
userVideo.current.srcObject=流;
userStream.current=流;
socketRef.current=socketIOClient.connect(端点);
socketRef.current.emit(“加入房间”,道具房间);
socketRef.current.on('other user',userID=>{
callUser(用户标识);
otherUser.current=用户ID;
});
socketRef.current.on(“用户已加入”,userID=>{
otherUser.current=用户ID;
});
socketRef.current.on(“要约”,HandlerRecieveCall);
socketRef.current.on(“应答”,handleAnswer);
socketRef.current.on(“ice候选者”,handleNewICECandidateMsg);
});
}, []);
函数callUser(用户ID){
console.log(“调用用户----d-s-d-s-d--sd-sdd-sd--”);
peerRef.current=createPeer(userID);
userStream.current.getTracks().forEach(track=>peerRef.current.addTrack(track,userStream.current));
}
函数createPeer(userID){
const peer=new rtpeerconnection({
//SDP指令:“统一计划”,
ICEServer:[
{
网址:“stun:stun.stunprotocol.org”
},
{
URL:'turn:numb.viagenie.ca',
凭证:“muazkh”,
用户名:'webrtc@live.com'
},
]
});
peer.onicecandidate=handleicecandidate事件;
peer.ontrack=手持支架通风口;
peer.onnegotiationneeded=()=>{
如果(peer.signalingState!=“稳定”)返回;
handlenegotiationneedevent(userID);
}
返回同伴;
}
函数handlenegotiationneedEvent(userID){
log(“negotiationsad-das-d-as-d-asd--asd-a-sd-a-sd-”;
peerRef.current.createOffer()。然后(offer=>{
返回peerRef.current.setLocalDescription(offer);
}).然后(()=>{
常数有效载荷={
目标:用户ID,
输入:“视频优惠”,
调用方:socketRef.current.id,
sdp:peerRef.current.localDescription
};
socketRef.current.emit(“提供”,有效载荷);
}).catch(e=>console.log(e));
}
函数handleRecieveCall(传入){
peerRef.current=createPeer();
const desc=新的RTCSessionDescription(incoming.sdp);
peerRef.current.setRemoteDescription(desc).then(()=>{
userStream.current.getTracks().forEach(track=>peerRef.current.addTrack(track,userStream.current));
}).然后(()=>{
返回peerRef.current.createAnswer();
})。然后(答案=>{
返回peerRef.current.setLocalDescription(应答);
}).然后(()=>{
常数有效载荷={
目标:传入.caller,
输入:“视频优惠”,
调用方:socketRef.current.id,
sdp:peerRef.current.localDescription
}
socketRef.current.emit(“应答”,有效载荷);
})
}
功能手柄(信息){
const desc=新的RTCSessionDescription(message.sdp);
peerRef.current.setRemoteDescription(desc.catch)(e=>console.log(e));
}
函数handleICECandidateEvent(e){
如果(如候选人){
常数有效载荷={
目标:otherUser.current,
候选人:e.候选人,
}
socketRef.current.emit(“ice候选者”,有效载荷);
}
}
函数handleNewICECandidateMsg(传入){
const-candidate=新的RTCIceCandidate(传入);
if(peerRef.current&&候选者){
peerRef.current.addIceCandidate(候选者).catch(e=>console.log(e));
}
}
功能手柄支架通风口(e){
var-stream=e.streams[0];
var tracks=stream.getTracks();
var lun=tracks.length;
控制台日志(轨道);
如果(lun==2){
partnerVideo.current.srcObject=流;
}else if(lun==1){
screenShare.current.srcObject=流;
}
};
函数shareScreen(){
navigator.mediaDevices.getDisplayMedia({cursor:true})。然后(stream=>{
screenShare.current.srcObject=流;
userScreen.current=流;
const screenTrack=stream.getTracks()[0];
callUser(otherUser.current);
peerRef.current.addTrack(屏幕跟踪、流);
screenstrack.onended=函数(){
peerRef.current.removeTrack(屏幕跟踪);
}
})
}
返回(
共享屏幕
);
}) 在
shareScreen
中,您正在使用addTrack
向现有对等连接添加第二个磁道,这将触发重新协商(使您的onnegotiationneeded
处理程序再次运行)。到目前为止,这是正确的,并触发第二次提供/应答交换,这是添加媒体曲目所需的
您只是没有正确地处理重新协商,因为您将初始化代码与(重新)协商代码混合在一起,导致在已有对象时创建新的rtpeerconnection
对象
每当您添加磁道或停止其底层收发器时,就会发生重新协商,因此您不希望协商代码中包含初始化代码。而是这样做:
RTPeerConnection
的创建移出HandlerReceiveCall
。Cre