peer.js webrtc >> 在运行时改变流

peer.js webrtc >> changing stream in runtime

我正在使用 peer.js 和 webrtc 开发跨平台应用程序。 我正在使用科尔多瓦,人行横道。 另外我正在使用 webrtc 适配器 (https://github.com/webrtc/adapter)

我的代码基于 webrtc-crosswalk 示例。 (https://github.com/crosswalk-project/crosswalk-samples)

我想在不创建新呼叫的情况下更改流的视频源。 我的方法是删除流的轨道并添加另一台摄像机的新轨道。 结果是本地视频显示正确内容,被叫远程视频卡顿

可能我犯了一个非常基本的错误,但我找不到解决办法。 我期待着您的回答和解决方案。

附上我的主要代码文件。

//Notwendig, um die Dialogfunktion zu aktivieren
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
    console.log(navigator.notification);
    // Now safe to use device APIs
}


document.addEventListener('DOMContentLoaded', function () {
    // PeerJS server location
    var SERVER_IP = '172.20.37.147';
    var SERVER_PORT = 9000;

    // DOM elements manipulated as user interacts with the app
    var messageBox = document.querySelector('#messages');
    var callerIdEntry = document.querySelector('#caller-id');
    var connectBtn = document.querySelector('#connect');
    var recipientIdEntry = document.querySelector('#recipient-id');
    var dialBtn = document.querySelector('#dial');
    var remoteVideo = document.querySelector('#remote-video');
    var localVideo = document.querySelector('#local-video');
    var cameraTurn = document.querySelector('#camera_turn');
    var stop = document.querySelector('#stop');

    // the default facing direction
    var dir = "environment";

    // the ID set for this client
    var callerId = null;



    // PeerJS object, instantiated when this client connects with its
    // caller ID
    var peer = null;


    // the local video stream captured with getUserMedia()
    var localStream = null;

    // DOM utilities
    var makePara = function (text) {
        var p = document.createElement('p');
        p.innerText = text;
        return p;
    };

    var addMessage = function (para) {
        if (messageBox.firstChild) {
            messageBox.insertBefore(para, messageBox.firstChild);
        }
        else {
            messageBox.appendChild(para);
        }
    };

    var logError = function (text) {
        var p = makePara('ERROR: ' + text);
        p.style.color = 'red';
        addMessage(p);
    };

    var logMessage = function (text) {
        addMessage(makePara(text));
    };

    // get the local video and audio stream and show preview in the
    // "LOCAL" video element
    // successCb: has the signature successCb(stream); receives
    // the local video stream as an argument
    var getLocalStream = function (successCb, ask = true) {
        if (localStream && successCb) {
            successCb(localStream);
        }
        else {
          
                navigator.mediaDevices.getUserMedia({ audio: true, video: { facingMode: dir } })
                    .then(function (stream) {

                        if (localStream == null) {
                            /* use the stream */
                            localStream = stream;
                        }
                        else {
                         
                            stream.getTracks().forEach(function (track) {
                                localStream.addTrack(track);
                            });
                        }


                        localVideo.src = window.URL.createObjectURL(localStream);

                        if (successCb) {
                            successCb(stream);
                        }
                    })
                    .catch(function (err) {
                        /* handle the error */
                        logError('failed to access local camera');
                        logError(err.message);
                    });
            }
           
        
    };

    // set the "REMOTE" video element source
    var showRemoteStream = function (stream) {
        remoteVideo.src = window.URL.createObjectURL(stream);
    };

    // set caller ID and connect to the PeerJS server
    var connect = function () {
        callerId = callerIdEntry.value;

        if (!callerId) {
            logError('please set caller ID first');
            return;
        }

        try {
            // create connection to the ID server
            peer = new Peer(callerId, { host: SERVER_IP, port: SERVER_PORT });

            // hack to get around the fact that if a server connection cannot
            // be established, the peer and its socket property both still have
            // open === true; instead, listen to the wrapped WebSocket
            // and show an error if its readyState becomes CLOSED
            peer.socket._socket.onclose = function () {
                logError('no connection to server');
                peer = null;
            };

            // get local stream ready for incoming calls once the wrapped
            // WebSocket is open
            peer.socket._socket.onopen = function () {
                getLocalStream();
            };

            // handle events representing incoming calls
            peer.on('call', answer);
        }
        catch (e) {
            peer = null;
            logError('error while connecting to server');
        }
    };

    // make an outgoing call
    var dial = function () {
        if (!peer) {
            logError('please connect first');
            return;
        }

        if (!localStream) {
            logError('could not start call as there is no local camera');
            return
        }

        var recipientId = recipientIdEntry.value;

        if (!recipientId) {
            logError('could not start call as no recipient ID is set');
            return;
        }

        getLocalStream(function (stream) {
            logMessage('outgoing call initiated');

            var call = peer.call(recipientId, stream);

            call.on('stream', showRemoteStream);

            call.on('error', function (e) {
                logError('error with call');
                logError(e.message);
            });
        });
    };




    // answer an incoming call
    var answer = function (call) {
        if (!peer) {
            logError('cannot answer a call without a connection');
            return;
        }

        if (!localStream) {
            logError('could not answer call as there is no localStream ready');
            return;
        }


        //Asks user to answer the call
        navigator.notification.confirm(
            "Receive a call?",
            function (buttonIndex) {
                if (buttonIndex === 1) {
                    //user clicked "yes"
                    logMessage('incoming call answered');

                    call.on('stream', showRemoteStream);

                    call.answer(localStream);
                }
                else {
                    //user clicked "no"
                    logMessage('incoming call denied');
                }
            }
            ,
            'Incoming Call',
            ['Yes', 'No']
        );

    };



    function turnDirection() {
        if (dir === "user")
            return "environment";
        else
            return "user";
    }

    var turnCamera = function (call) {
        dir = turnDirection();
        localStream.getTracks().forEach(function (track) {
            track.stop();
            localStream.removeTrack(track);
        });
        getLocalStream(false);
        

    };
    var stopCall = function (call) { };
    // wire up button events
    connectBtn.addEventListener('click', connect);
    dialBtn.addEventListener('click', dial);
    cameraTurn.addEventListener('click', turnCamera);
    stop.addEventListener('click', stopCall);
});

如果您删除然后将新轨道添加到 PeerConnection,您需要重新协商 offer-answer 才能使其正常工作。我会建议您使用 replaceTrack API 来避免 re-negotiation 在更改相机输入时出现的问题。