Javascript 如何发送和接收通过getUsermedia()生成的桌面捕获流

Javascript 如何发送和接收通过getUsermedia()生成的桌面捕获流,javascript,socket.io,webrtc,Javascript,Socket.io,Webrtc,我正在用WebRTC+Socket.io制作一个屏幕共享应用程序,并被卡在一个地方。 使用WebRTC+Socket.io与两个浏览器连接,可以发送文本 我正在接受来自的支持,但不支持stream。(如果解决方案基于此链接,则非常有用) 如何发送getUserMedia()流: 并在channel.onmessage()上接收相同的流: 我将event.data作为“[object MediaStream]”而不是流获取 channel.onmessage = function(event){

我正在用WebRTC+Socket.io制作一个屏幕共享应用程序,并被卡在一个地方。 使用WebRTC+Socket.io与两个浏览器连接,可以发送文本

我正在接受来自的支持,但不支持stream。(如果解决方案基于此链接,则非常有用)

如何发送getUserMedia()流:

并在channel.onmessage()上接收相同的流: 我将event.data作为“[object MediaStream]”而不是流获取

channel.onmessage = function(event){
  // unable to get correct stream
  // event.data is "[object MediaStream]"  in string
}

function createPeerConnection(isInitiator, config) {
    console.log('Creating Peer connection as initiator?', isInitiator, 'config:', config);
    peerConn = new RTCPeerConnection(config);

    // send any ice candidates to the other peer
    peerConn.onicecandidate = function (event) {
        console.log('onIceCandidate event:', event);
        if (event.candidate) {
            sendMessage({
                type: 'candidate',
                label: event.candidate.sdpMLineIndex,
                id: event.candidate.sdpMid,
                candidate: event.candidate.candidate
            });
        } else {
            console.log('End of candidates.');
        }
    };

    if (isInitiator) {
        console.log('Creating Data Channel');
        dataChannel = peerConn.createDataChannel("screen");
        onDataChannelCreated(dataChannel);

        console.log('Creating an offer');
        peerConn.createOffer(onLocalSessionCreated, logError);
    } else {
        peerConn.ondatachannel = function (event) {
            console.log('ondatachannel:', event.channel);
            dataChannel = event.channel;
            onDataChannelCreated(dataChannel);
        };
    }
}
它对字符串或json(即dataChannel.send('Hello')工作正常

我已经为相同的内容创建了wiki页面:


请帮助。

请尝试以下操作:(代码末尾的解释

  • 您必须使用
    peer.addTrack
    附加流,如上面的示例所示
  • 您必须使用
    peer.ontrack
    接收远程流,如上面的示例所示
  • i、 e.使用
    addTrack
    连接摄像机,使用
    ontrack
    接收远程摄像机

    决不能使用
    dataChannel.send
    发送流。两者都是完全不同的协议。必须使用RTP共享
    MediaStream
    ;不是SCTP。只有在调用
    peer.addTrack
    方法来附加相机流时,才会使用RTP

    此过程发生在您打开或加入房间之前

    请参见此处的单页演示:

    上述代码段的HTML:

    <button id="share-your-camera"></button>
    <video id="local-video" controls autoplay playsinline></video>
    <video id="remote-video" controls autoplay playsinline></video>
    
    
    
    非常感谢Muaz。亲爱的Mauz实际上我看到了一个例子,我可以在不使用addTrack()和ontrack()的情况下共享屏幕流。我真的很困惑他们在遵循/使用哪个概念/算法/协议。codelab使用旧的addStream API,该API已被弃用。
    var btnShareYourCamera = document.querySelector('#share-your-camera');
    var localVideo = document.querySelector('#local-video');
    var remoteVideo = document.querySelector('#remote-video');
    
    var websocket = new WebSocket('wss://path-to-server:port/');
    websocket.onmessage = function(event) {
        var data = JSON.parse(event.data);
        if (data.sdp) {
            if (data.sdp.type === 'offer') {
                getUserMedia(function(video_stream) {
                    localVideo.srcObject = video_stream;
                    answererPeer(new RTCSessionDescription(data.sdp), video_stream);
                });
            }
    
            if (data.sdp.type === 'answer') {
                offerer.setRemoteDescription(new RTCSessionDescription(data.sdp));
            }
        }
    
        if (data.candidate) {
            addIceCandidate((offerer || answerer), new RTCIceCandidate(data.candidate));
        }
    };
    
    var iceTransportPolicy = 'all';
    var iceTransportLimitation = 'udp';
    
    function addIceCandidate(peer, candidate) {
        if (iceTransportLimitation === 'tcp') {
            if (candidate.candidate.toLowerCase().indexOf('tcp') === -1) {
                return; // ignore UDP
            }
        }
    
        peer.addIceCandidate(candidate);
    }
    
    var offerer, answerer;
    
    var iceServers = {
        iceServers: [{
            'urls': [
                'stun:stun.l.google.com:19302',
                'stun:stun1.l.google.com:19302',
                'stun:stun2.l.google.com:19302',
                'stun:stun.l.google.com:19302?transport=udp',
            ]
        }],
        iceTransportPolicy: iceTransportPolicy,
        rtcpMuxPolicy: 'require',
        bundlePolicy: 'max-bundle'
    };
    
    // https://https;//cdn.webrtc-experiment.com/IceServersHandler.js
    if (typeof IceServersHandler !== 'undefined') {
        iceServers.iceServers = IceServersHandler.getIceServers();
    }
    
    var mediaConstraints = {
        OfferToReceiveAudio: true,
        OfferToReceiveVideo: true
    };
    
    /* offerer */
    
    function offererPeer(video_stream) {
        offerer = new RTCPeerConnection(iceServers);
        offerer.idx = 1;
    
        video_stream.getTracks().forEach(function(track) {
            offerer.addTrack(track, video_stream);
        });
    
        offerer.ontrack = function(event) {
            remoteVideo.srcObject = event.streams[0];
        };
    
        offerer.onicecandidate = function(event) {
            if (!event || !event.candidate) return;
            websocket.send(JSON.stringify({
                candidate: event.candidate
            }));
        };
    
        offerer.createOffer(mediaConstraints).then(function(offer) {
            offerer.setLocalDescription(offer).then(function() {
                websocket.send(JSON.stringify({
                    sdp: offer
                }));
            });
        });
    }
    
    /* answerer */
    
    function answererPeer(offer, video_stream) {
        answerer = new RTCPeerConnection(iceServers);
        answerer.idx = 2;
    
        video_stream.getTracks().forEach(function(track) {
            answerer.addTrack(track, video_stream);
        });
    
        answerer.ontrack = function(event) {
            remoteVideo.srcObject = event.streams[0];
        };
    
        answerer.onicecandidate = function(event) {
            if (!event || !event.candidate) return;
            websocket.send(JSON.stringify({
                candidate: event.candidate
            }));
        };
    
        answerer.setRemoteDescription(offer).then(function() {
            answerer.createAnswer(mediaConstraints).then(function(answer) {
                answerer.setLocalDescription(answer).then(function() {
                    websocket.send(JSON.stringify({
                        sdp: answer
                    }));
                });
            });
        });
    }
    
    var video_constraints = {
        mandatory: {},
        optional: []
    };
    
    function getUserMedia(successCallback) {
        function errorCallback(e) {
            alert(JSON.stringify(e, null, '\t'));
        }
    
        var mediaConstraints = {
            video: true,
            audio: true
        };
    
        navigator.mediaDevices.getUserMedia(mediaConstraints).then(successCallback).catch(errorCallback);
    }
    
    btnShareYourCamera.onclick = function() {
        getUserMedia(function(video_stream) {
            localVideo.srcObject = video_stream;
            offererPeer(video_stream);
        });
    };
    
    <button id="share-your-camera"></button>
    <video id="local-video" controls autoplay playsinline></video>
    <video id="remote-video" controls autoplay playsinline></video>