未捕获(承诺)无法在“RTCPeerConnection”上执行“setRemoteDescription”:无法设置远程应答 sdp:在错误状态下调用:稳定

问题描述 投票:0回答:0

我是 webrtc 的新手,当我执行我的演示时,显示这样的错误消息:

未捕获(承诺)DOMException:无法在“RTCPeerConnection”上执行“addIceCandidate”:远程描述为空

未捕获(承诺)DOMException:无法在“RTCPeerConnection”上执行“setRemoteDescription”:无法设置远程应答 sdp:在错误状态下调用:稳定

请帮忙!!!如果你能告诉我代码。非常感谢。

执行顺序不对吗?

在线演示: https://139.198.176.37/charclient/webrtc/p2p.html?type=offer 或 type=answer

我的服务器代码:

package com.demo.socketio;
import com.corundumstudio.socketio.SocketConfig;
import com.corundumstudio.socketio.SocketIONamespace;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.Transport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SocketioConfig {
private static final Logger log = LoggerFactory.getLogger(SocketioConfig.class);
@Bean
public SocketIOServer socketIOServer(SocketioServerProperties config) {
    config.setOrigin(null);   // 注意如果开放跨域设置,需要设置为null而不是"*"
    config.setTransports(Transport.POLLING, Transport.WEBSOCKET);
    SocketConfig socketConfig = config.getSocketConfig();
    socketConfig.setReuseAddress(true);
    final SocketIOServer server = new SocketIOServer(config);
    server.start();
    return server;

}
/**
 * @param server
 * @return
 */
@Bean
public SocketIONamespace socketIOChats(SocketIOServer server) {
    SocketIONamespace n = server.addNamespace("/chattest");
    n.addConnectListener(client -> {
        log.info("**********connection success:" + client.getHandshakeData().getSingleUrlParam("roomid"));

    });
    n.addEventListener("message", Object.class, (client, data, ackRequest) -> {  //new DataListener<MessageBase>() {
        log.info("message client: {}", data);
        n.getBroadcastOperations().sendEvent("message", data);
    });
    n.addDisconnectListener(client -> {
        log.info("Disconnect success", client.getSessionId());
    });
    return n;
}}

我的 html 客户端代码:

<script src="../js/adapter.js"></script>
<script src="../js/socket.io/socket.io.js"></script>
<video id="remote-video"></video>
<video id="local-video" muted></video>
<button class="start-button" onclick="startLive()">start</button>

<script>
const message = {
    el: document.querySelector('.logger'),
    log (msg) {
        this.el.innerHTML += `<span>${new Date().toLocaleTimeString()}:${msg}</span><br/>`;
    },
    error (msg) {
        this.el.innerHTML += `<span class="error">${new Date().toLocaleTimeString()}:${msg}</span><br/>`;
    }
};
const pcConfig = {
    'iceServers': [{
        'urls': 'turn:stun.ukerd.com:3478',// 免费直接可用的iceserver列表  https://gist.github.com/yetithefoot/7592580,也可以自建
        'credential': "123456",
        'username': "lvming"
    }]
};
const target = location.search.slice(6);
console.log('target is :'+target)
const localVideo = document.querySelector('#local-video');
const remoteVideo = document.querySelector('#remote-video');
const button = document.querySelector('.start-button');

localVideo.onloadeddata = () => {
    message.log('播放本地视频');
    localVideo.play();
}
remoteVideo.onloadeddata = () => {
    message.log('播放对方视频');
    remoteVideo.play();
}

document.title = target === 'offer' ? '发起方' : '接收方';

message.log('第一步:信令通道(WebSocket)创建中......');
const socket = io.connect('https://139.198.176.37/chattest', {
    transports: ['websocket', 'xhr-polling', 'jsonp-polling'],
    path: "/socket.ix/"
});
socket.on('connect', function () {
    message.log('第二步:信令通道创建成功!');
    target === 'offer' && (button.style.display = 'block');
});
socket.on('error', function (e) {
    message1.error('信令通道创建失败!'+e);
});
socket.on('message', function (e) {
    const { type, sdp, iceCandidate } = JSON.parse(e)  //e.data
    console.log('type is :'+type)
    console.log('sdp is :'+sdp)
    console.log('iceCandidate is :'+iceCandidate)
    console.log('start and end')
    if (type === 'answer') {
        peer.setRemoteDescription(new RTCSessionDescription({ type, sdp }));
    } else if (type === 'answer_ice') {
        peer.addIceCandidate(iceCandidate);
    } else if (type === 'offer') {
        startLive(new RTCSessionDescription({ type, sdp }));
    } else if (type === 'offer_ice') {
        peer.addIceCandidate(iceCandidate);
    }
});


const peer = new RTCPeerConnection(pcConfig);
peer.ontrack = e => {
    if (e && e.streams) {
        message.log('收到对方音频/视频流数据...');
        remoteVideo.srcObject = e.streams[0];
    }
};

peer.onicecandidate = e => {
    if (e.candidate) {
        message.log('搜集并发送候选人');
        socket.send(JSON.stringify({
            type: `${target}_ice`,
            iceCandidate: e.candidate
        }));
    } else {
        message.log('候选人收集完成!');
    }
};

async function startLive (offerSdp) {
    target === 'offer' && (button.style.display = 'none');
    let stream;
    try {
        message.log('尝试调取本地摄像头/麦克风');
        stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
        message.log('摄像头/麦克风获取成功!');
        localVideo.srcObject = stream;
    } catch(err) {
        console.log(err);
        message.error('摄像头/麦克风获取失败!');
        return;
    }

    message.log(`------ WebRTC ${target === 'offer' ? '发起方' : '接收方'}流程开始 ------`);
    message.log('将媒体轨道添加到轨道集');
    stream.getTracks().forEach(track => {
        peer.addTrack(track, stream);
    });
    //发起方 offer
    if (!offerSdp) {
        message.log('创建本地SDP');
        const offer = await peer.createOffer();
        await peer.setLocalDescription(offer);
        message.log(`传输发起方本地SDP`);
        socket.send(JSON.stringify(offer));
    } else {//接收方
        message.log('接收到发送方SDP');
        await peer.setRemoteDescription(offerSdp);

        message.log('创建接收方(应答)SDP');
        const answer = await peer.createAnswer();
        message.log(`传输接收方(应答)SDP`);
        socket.send(JSON.stringify(answer));
        await peer.setLocalDescription(answer);
    }
}
</script>
javascript java webrtc
© www.soinside.com 2019 - 2024. All rights reserved.