基于Amazon Kinesis Video Streams WebRTC SDK的远程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:
同时要确保Master端也处理接收到的新ICE候选。peerConnection.onicecandidate = event => { if (event.candidate) { // 需要传入Master的clientId,可从信令交互中获取 signalingClient.sendIceCandidate(event.candidate, masterClientId); } };
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

