作者:Philipp Hancke(原文链接)
翻译:刘通
原标题:When should you display incoming WebRTC video
自2011年的第一个版本以来,WebRTC规范已经发生了很大的变化。Jan-Ivar对多年来WebRTC的演变情况进行了精彩的总结,详见这篇文章。
Web开发人员的核心问题之一是何时显示传入的视频流。
在第一版本中,规范有一个addstream事件,这是在设置远程描述时出发的。Addstream事件有一个流对象,你可以将视频元素的srcObject属性设置为该流对象,如下所示(使用更现代但相似的轨道事件):
1const pc1 = new RTCPeerConnection(), pc2 = new RTCPeerConnection();
2
3pc2.ontrack = e => {
4 console.log('got track', e.track, e.streams);
5 remoteVideo.srcObject = e.streams[0];
6};
7
8pc2.oniceconnectionstatechange = () =>
9 console.log('PC2 ice state ' + pc2.iceConnectionState);
10
11(async () => {
12 const stream = await navigator.mediaDevices.getUserMedia({video: true});
13 pc1.addTrack(stream.getVideoTracks()[0], stream);
14 const offer = await pc1.createOffer();
15 await pc1.setLocalDescription(offer);
16 await pc2.setRemoteDescription(offer);
17 const answer = await pc2.createAnswer();
18 await pc2.setLocalDescription(answer);
19 await pc1.setRemoteDescription(answer);
20})();
21
22const console = {log: msg => div.innerHTML += msg + "<br>"};
处于演示的目的,这个小代码没有完成两个本地对象之间的WebRTC连接。它永远不会连接ICE候选。“Result”标签显示我们得到了轨道事件,即使连接从未成功。在WebRTC的早期,有很多像“远程视频是个黑箱”这样的情况。特别是当点对点连接失败时发生这种情况。比如当防火墙阻拦了什么的时候:
为了检测到这点,必须监听iceconnectionstatechange事件并对其进行评估。状态演示显示如何监听这种状态变化。当对等连接的iceConnectionState属性更改为“connected”或者“completed”时会显示视频。在仅有单个流的简单情况下,这种方式非常有效。
对于多个流,以及将流添加到正在进行的连接时,这将不再起作用。新流的开始处用户可能会遇到非常短暂的黑屏时间。此外,我们的视频元素现在必须能够访问对等连接状态,并说明它甚至不代表正确的事情。
轨道静音属性来解决
在规范的最新版本中—在Firefox 59版本中实现的收发器模型—MediaStreamTrack具有静音属性。此属性最初设置为true,一旦媒体到达,它将变为false。有关详细信息,请参阅规范中的RTCRTPReceiver。
这可以更好地决定何时显示视频元素以及何时通过监听MediaStreamTrack上的非静音和静音事件来隐藏它,如下所示:
1const pc1 = new RTCPeerConnection(), pc2 = new RTCPeerConnection();
2
3pc2.ontrack = e => {
4 console.log('track event muted = ' + e.track.muted);
5 e.track.onunmute = () => {
6 console.log('track unmuted');
7 remoteVideo.srcObject = e.streams[0];
8 }
9};
10
11pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
12pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
13pc2.oniceconnectionstatechange = () =>
14 console.log('PC2 ice state ' + pc2.iceConnectionState);
15
16(async () => {
17 const stream = await navigator.mediaDevices.getUserMedia({video: true});
18 pc1.addTrack(stream.getVideoTracks()[0], stream);
19 await pc1.setLocalDescription(await pc1.createOffer());
20 await pc2.setRemoteDescription(pc1.localDescription);
21 await pc2.setLocalDescription(await pc2.createAnswer());
22 await pc1.setRemoteDescription(pc2.localDescription);
23})();
24const console = {log: msg => div.innerHTML += msg + "<br>"};
我们在上面的“Result”标签中的日志输出中看到的是,在对等连接变为已连接之后,轨道最初被静音并且只有在视频数据包到达时才被解除静音。
不幸的是,这只适用于Firefox 59及更高版本。有一个Chrome / WebRTC bug以及Microsoft Edge的ORTC实现中存在类似的问题。希望围绕此问题的错误很快就会解决,但它是向WebRTC 1.0过渡的一个小而关键的细节。