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