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

基于Amazon Kinesis Video Streams WebRTC SDK的远程Viewer视频加载失败排查

跨机器远程场景下KVS WebRTC Viewer连接失败问题排查

问题描述

使用amazon-kinesis-video-streams-webrtc-sdk-js时,本地环境(Viewer与Master在同一机器或浏览器不同标签页)视频流可正常运行,但跨机器(远程)场景下无法工作。仅远程Viewer端的event.currentTarget.connectionState会在5秒后返回failed状态,调用peerConnection.restartIce()也完全无效。

用户提供的Viewer端代码

function openSignalingViewer(channelARN, channelEndpoint, configuration, onRemoteDataMessage) {
    const peerConnection = new RTCPeerConnection(configuration);
    peerConnection.ondatachannel = event => {
        event.channel.onmessage = onRemoteDataMessage
    }
    dataChannels['proctor'] = peerConnection.createDataChannel('kvsDataChannel')

    const signalingClient = new SignalingClient({
        ...config,
        channelARN,
        channelEndpoint,
        clientId: getRandomClientId(),
        role: ChannelRole.VIEWER
    })

    signalingClient.on('open', async () => {
        // Create an SDP offer to send to the master
        await peerConnection.setLocalDescription(
            await peerConnection.createOffer({
                offerToReceiveAudio: true,
                offerToReceiveVideo: true,
            }),
        );
        signalingClient.sendSdpOffer(peerConnection.localDescription);
    });
    signalingClient.on('sdpAnswer', async answer => {
        // Add the SDP answer to the peer connection
        await peerConnection.setRemoteDescription(answer);
    });

    signalingClient.on('iceCandidate', async (candidate, remoteClientId) => {
        await peerConnection.addIceCandidate(candidate)
    })

    peerConnection.addEventListener('track', event => {
        config.remoteView.srcObject = event.streams[0];
    });
    peerConnection.addEventListener('connectionstatechange', event => {
        if (event.currentTarget.connectionState === 'failed') {
            console.log('restarting')
            peerConnection.restartIce()
        }
    });
    signalingClient.on('error', error => {
        console.log('error', error)
    })
    signalingClient.open()
    return signalingClient
}

代码问题排查与修复建议

1. ICE服务器配置缺失(核心问题)

本地场景下设备在同一网络,无需STUN/TURN就能连通,但远程跨网络必须依赖STUN穿透NAT,复杂网络还需要TURN中转。你的代码直接使用传入的configuration,如果调用方没配置iceServers,远程连接必然失败。

  • 修复:要么要求调用方传入包含STUN/TURN的配置,要么在代码中默认添加公共STUN服务器:
    if (!configuration.iceServers || !configuration.iceServers.length) {
        configuration.iceServers = [{ urls: 'stun:stun.l.google.com:19302' }];
    }
    

2. DataChannel创建时机错误

Viewer作为接收方,不应该主动创建DataChannel。WebRTC中通常由发起方(Master)创建DataChannel,Viewer通过ondatachannel事件接收即可。你主动创建的行为会打乱协商流程,导致远程连接失败。

  • 修复:移除dataChannels['proctor'] = peerConnection.createDataChannel('kvsDataChannel')这行代码,改为在ondatachannel事件中保存通道:
    peerConnection.ondatachannel = event => {
        event.channel.onmessage = onRemoteDataMessage;
        dataChannels['proctor'] = event.channel;
    }
    

3. restartIce逻辑不完整

仅调用restartIce()只会生成新的ICE候选,但没有将这些新候选通过信令发送给Master,Master收不到自然无法完成重连。

  • 修复:添加icecandidate事件监听,将新候选发送给Master:
    peerConnection.onicecandidate = event => {
        if (event.candidate) {
            // 需要传入Master的clientId,可从信令交互中获取
            signalingClient.sendIceCandidate(event.candidate, masterClientId);
        }
    };
    
    同时要确保Master端也处理接收到的新ICE候选。

4. 异步操作无错误捕获

代码中setLocalDescription、addIceCandidate等异步操作没有错误捕获,一旦出错会直接中断流程,还看不到具体报错信息。

  • 修复:给所有异步操作加上try/catch:
    signalingClient.on('open', async () => {
        try {
            const offer = await peerConnection.createOffer({
                offerToReceiveAudio: true,
                offerToReceiveVideo: true,
            });
            await peerConnection.setLocalDescription(offer);
            signalingClient.sendSdpOffer(peerConnection.localDescription);
        } catch (err) {
            console.error('SDP Offer创建/设置失败:', err);
        }
    });
    

5. SignalingClient配置变量混淆

代码中用...config扩展SignalingClient配置,但这个config和后面的config.remoteView是同一个变量,大概率包含的是视图配置而非SignalingClient需要的AWS凭证、区域等参数,会导致信令连接异常。

  • 修复:明确区分配置变量,比如传入单独的signalingConfig参数,或者直接写出必要配置:
    const signalingClient = new SignalingClient({
        channelARN,
        channelEndpoint,
        clientId: getRandomClientId(),
        role: ChannelRole.VIEWER,
        accessKeyId: '你的AWS AccessKey',
        secretAccessKey: '你的AWS SecretKey',
        region: '通道所在区域'
    });
    

额外排查建议

  • 去浏览器的WebRTC内部页面(Chrome:chrome://webrtc-internals/)查看详细日志,确认ICE候选是否正常收集、STUN/TURN是否连通。
  • 检查Master端代码,确保Master也配置了正确的ICE服务器,并且能正确处理Viewer发送的ICE候选和SDP信息。
  • 确认AWS Kinesis Video Streams通道的权限配置,两端使用的凭证必须有权限访问该通道。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 06:57:08