Javascript WebRTC 2路视频无法设置远程应答sdp:在错误状态下调用:kStable

Javascript WebRTC 2路视频无法设置远程应答sdp:在错误状态下调用:kStable,javascript,webrtc,Javascript,Webrtc,嗨,我正试图建立一个视频聊天使用WebRTC与信号器的信号,它的基础上 错误是: setRemoteDescription:InvalidStateError:设置远程应答失败 sdp:在错误状态下调用:kStable onError@webrtc.js:26 pc.setRemoteDescription.error@webrtc.js:101 2webrtc.js:26 func LOCALDESCREATED:操作错误:无法设置本地应答sdp: 在错误状态下调用:kStable onErr

嗨,我正试图建立一个视频聊天使用WebRTC与信号器的信号,它的基础上 错误是:

setRemoteDescription:InvalidStateError:设置远程应答失败 sdp:在错误状态下调用:kStable onError@webrtc.js:26 pc.setRemoteDescription.error@webrtc.js:101 2webrtc.js:26

func LOCALDESCREATED:操作错误:无法设置本地应答sdp: 在错误状态下调用:kStable onError@webrtc.js:26 pc.setLocalDescription.error@webrtc.js:115 3webrtc.js:26

createAnswer:InvalidStateError:PeerConnection无法创建 在非远程报价或本地pranswer的州应答

还有我的js(请原谅一团糟!):


如果对方是报价人,请手动创建报价,而不是在onnegotiationneeded函数中创建报价,有时会调用onnegotiationneeded两次,从而导致您面临的错误。
// Generate random room name if needed
if (!location.hash) {
    location.hash = Math.floor(Math.random() * 0xFFFFFF).toString(16);
}
const roomHash = location.hash.substring(1);

const roomName = 'test';
const configuration = {
    iceServers: [
        {
            'urls': [
                'stun:74.125.142.127:19302',
                'stun:23.21.150.121:3478'

                ]
        }
    ]
};
let room;
let pc;


function onSuccess() { };
function onError(context, error) {
    console.error(`${context} : ${error}`);
};

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/video")
    .build();


connection.on('Start', () => {
    connection.invoke('JoinRoom', roomName).catch(error => onError("on invoke join room",error));
    connection.invoke('GetMembers', roomName).catch(error => onError("on invoke GetMembers",error));
});
connection.on('members',
    users => {
        console.log('MEMBERS', users);
        // If we are the second or greater user to connect to the room we will be creating the offer
        users = JSON.parse(users);
        const isOfferer = users.length === 2 ? true : false;
        console.log("isOfferer", isOfferer);
        console.log("users length = ", users.length);
        startWebRTC(isOfferer);
    });

// Send signaling data via signalr
function sendMessage(message) {
    connection.invoke('send', message);
}

function startWebRTC(isOfferer) {
    pc = new RTCPeerConnection(configuration);

    // 'onicecandidate' notifies us whenever an ICE agent needs to deliver a
    // message to the other peer through the signaling server
    pc.onicecandidate = event => {
        if (event.candidate) {
            sendMessage(JSON.stringify({ 'candidate': event.candidate }));
            console.log("send message - ", { 'candidate': event.candidate });
        }
    };

    // If user is offerer let the 'negotiationneeded' event create the offer
    if (isOfferer) {
        pc.onnegotiationneeded = () => {
            pc.createOffer().then(localDescCreated).catch(error => onError("onnegotiationneeded",error));
        }
    }

    // When a remote stream arrives display it in the #remoteVideo element
    pc.ontrack = event => {
        const stream = event.streams[0];
        if (!remoteVideo.srcObject || remoteVideo.srcObject.id !== stream.id) {
            remoteVideo.srcObject = stream;
        }
    };

    navigator.mediaDevices.getUserMedia({
        audio: true,
        video: true,
    }).then(stream => {
        // Display your local video in #localVideo element
        localVideo.srcObject = stream;
        // Add your stream to be sent to the conneting peer
        stream.getTracks().forEach(track => pc.addTrack(track, stream));
    }, error => onError("adding media devices", error));

    // Listen to signaling data from Scaledrone
    connection.on('newMessage', (message) => {
        message = JSON.parse(message);
        if (message.sdp) {
            // This is called after receiving an offer or answer from another peer
            pc.setRemoteDescription(new RTCSessionDescription(message.sdp), () => {
                // When receiving an offer lets answer it
                if (pc.remoteDescription.type === 'offer') {
                    pc.createAnswer().then(localDescCreated).catch(error => onError("createAnswer", error));
                }
            }, error => onError("setRemoteDescription", error));
        } else if (message.candidate) {
            // Add the new ICE candidate to our connections remote description
            pc.addIceCandidate(
                new RTCIceCandidate(message.candidate), onSuccess, error => onError("addIceCandidate", error)
            );
        }
    });
}

function localDescCreated(desc) {
    pc.setLocalDescription(
        desc,
        () => sendMessage(JSON.stringify({ 'sdp': pc.localDescription })),
        error => onError("func localDescCreated", error)
    );
}
connection.start().catch(err => console.error(err.toString()));