You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨设备WebRTC PeerConnection连接随机失败排查求助

基于WebRTC的视频通话App跨设备连接问题

我正在为毕业设计开发一款基于WebRTC的视频通话App,同一设备的不同浏览器/标签页中运行完全正常,但跨设备呼叫时PeerConnection连接总是失败(线上公网地址和本地环境均出现此问题)。我使用的TURN服务器已通过Trickle ICE测试验证可用。

以下是创建和处理PeerConnection的流程代码:

呼叫函数

// Call Function
export const call = async (from, to) => {
    let configuration = {
        iceServers: [
            {
                urls: "stun:stun1.l.google.com:19302"
            },
            {
                urls: "turn:a.relay.metered.ca:80",
                username: "xxxxxxxxxx",
                credential: "xxxxxxxxxx",
            },
            {
                urls: "turn:a.relay.metered.ca:80?transport=tcp",
                username: "xxxxxxxxxx",
                credential: "xxxxxxxxxx",
            },
            {
                urls: "turn:a.relay.metered.ca:443",
                username: "xxxxxxxxxx",
                credential: "xxxxxxxxxx",
            },
            {
                urls: "turn:a.relay.metered.ca:443?transport=tcp",
                username: "xxxxxxxxxx",
                credential: "xxxxxxxxxx",
            },
        ],
    };

    const peer = new RTCPeerConnection(configuration);

    const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true })
    peer.addTrack(stream.getTracks()[0], stream)

    const offer = await peer.createOffer();

    let message = {
        id : 'call',
        from : from,
        to : to,
        sdpOffer : offer,
        state: 'req_calling'
    };
    sendMessage(message);
    
    await peer.setLocalDescription(offer);
    WebRtcPeer.addPeer(peer)
    
    peer.onicecandidate = function (event) {
        if (event.candidate) {
            const message = {
                id : 'onIceCandidate',
                candidate : event.candidate,
                to : to,
                from: from
            }
            sendMessage(message);
        }
    }

    // get to know when connected to peer
    peer.onconnectionstatechange = function (event) {
        console.log('masuk sono')
        if (peer.connectionState === 'connected') {
            const message = {
                id: 'peerConnected',
                from: localStorage.getItem('me'),
                to: localStorage.getItem('they')
            }
            sendMessage(message)
        }
    }
}

接听呼叫函数

// Answering Call Function

export const incomingCall = async (message) => {
    const configuration = {
        iceServers: [
            {
                urls: "stun:stun1.l.google.com:19302"
            },
            {
                urls: "turn:a.relay.metered.ca:80",
                username: "xxxxxxxxxx",
                credential: "xxxxxxxxxx",
            },
            {
                urls: "turn:a.relay.metered.ca:80?transport=tcp",
                username: "xxxxxxxxxx",
                credential: "xxxxxxxxxx",
            },
            {
                urls: "turn:a.relay.metered.ca:443",
                username: "xxxxxxxxxx",
                credential: "xxxxxxxxxx",
            },
            {
                urls: "turn:a.relay.metered.ca:443?transport=tcp",
                username: "xxxxxxxxxx",
                credential: "xxxxxxxxxx",
            },
        ],
    }

    // create peer using RTC
    const peer = new RTCPeerConnection(configuration);

    peer.setRemoteDescription(new RTCSessionDescription(message.sdpOffer))

    const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true })
    peer.addTrack(stream.getTracks()[0], stream)

    const answer = await peer.createAnswer();

    await peer.setLocalDescription(answer);

    WebRtcPeer.addPeer(peer)

    peer.onicecandidate = function (event) {
        if (event.candidate) {
            const msg = {
                id : 'onIceCandidate',
                candidate : event.candidate,
                to : message.from,
                from: message.to
            }
            sendMessage(msg);
        }
    }

    // get to know when connected to peer
    peer.onconnectionstatechange = function (event) {
        if (peer.connectionState === 'connected') {
            const message = {
                id: 'peerConnected',
                from: localStorage.getItem('me'),
                to: localStorage.getItem('they')
            }
            sendMessage(message)
        }
    }

    let response = {
        id: 'incomingCallResponse',
        from: message.from,
        callResponse: 'accept',
        sdpOffer: answer,
        state: 'acc_calling'
    }
    sendMessage(response);
    localStorage.setItem('they', message.from)
}

我的信令服务器会将收到的ICE候选存入CandidatesQueue,待呼叫被接受且对方PeerConnection创建完成后,再批量发送所有候选。

【更新】多次测试发现连接情况随机:有时能成功,有时失败;不同设备间呼叫方向不同结果也不同。请问问题出在TURN服务器还是代码逻辑?


内容的提问来源于stack exchange,提问作者agam theos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 13:02:50