本文共 6070 字,大约阅读时间需要 20 分钟。
zoom公司大家其实都知道,会议的体验很好,因为他们善用了datachannel,有兴趣大家可以仔细研究,推敲,到了今天,技术和核心技术得不到大家的理解,很多人依然认为技术可以获取,缺的是钱,事实上,两个都缺。sctp协议可以适用tcp,也可以使用udp,zoom公司在一个版本中使用datachannel传输RTP数据,原因是什么?为了体验和效率。
Realtime communication with WebRTC Realtime communication with WebRTC
'use strict';var localConnection;var remoteConnection;var sendChannel;var receiveChannel;var pcConstraint;var dataConstraint;var dataChannelSend = document.querySelector('textarea#dataChannelSend');var dataChannelReceive = document.querySelector('textarea#dataChannelReceive');var startButton = document.querySelector('button#startButton');var sendButton = document.querySelector('button#sendButton');var closeButton = document.querySelector('button#closeButton');startButton.onclick = createConnection;sendButton.onclick = sendData;closeButton.onclick = closeDataChannels;function enableStartButton() { startButton.disabled = false;}function disableSendButton() { sendButton.disabled = true;}function createConnection() { dataChannelSend.placeholder = ''; var servers = null; pcConstraint = null; dataConstraint = null; trace('Using SCTP based data channels'); // For SCTP, reliable and ordered delivery is true by default. // Add localConnection to global scope to make it visible // from the browser console. window.localConnection = localConnection = new RTCPeerConnection(servers, pcConstraint); trace('Created local peer connection object localConnection'); sendChannel = localConnection.createDataChannel('sendDataChannel', dataConstraint); trace('Created send data channel'); localConnection.onicecandidate = iceCallback1; sendChannel.onopen = onSendChannelStateChange; sendChannel.onclose = onSendChannelStateChange; // Add remoteConnection to global scope to make it visible // from the browser console. window.remoteConnection = remoteConnection = new RTCPeerConnection(servers, pcConstraint); trace('Created remote peer connection object remoteConnection'); remoteConnection.onicecandidate = iceCallback2; remoteConnection.ondatachannel = receiveChannelCallback; localConnection.createOffer().then( gotDescription1, onCreateSessionDescriptionError ); startButton.disabled = true; closeButton.disabled = false;}function onCreateSessionDescriptionError(error) { trace('Failed to create session description: ' + error.toString());}function sendData() { var data = dataChannelSend.value; sendChannel.send(data); trace('Sent Data: ' + data);}function closeDataChannels() { trace('Closing data channels'); sendChannel.close(); trace('Closed data channel with label: ' + sendChannel.label); receiveChannel.close(); trace('Closed data channel with label: ' + receiveChannel.label); localConnection.close(); remoteConnection.close(); localConnection = null; remoteConnection = null; trace('Closed peer connections'); startButton.disabled = false; sendButton.disabled = true; closeButton.disabled = true; dataChannelSend.value = ''; dataChannelReceive.value = ''; dataChannelSend.disabled = true; disableSendButton(); enableStartButton();}function gotDescription1(desc) { localConnection.setLocalDescription(desc); trace('Offer from localConnection \n' + desc.sdp); remoteConnection.setRemoteDescription(desc); remoteConnection.createAnswer().then( gotDescription2, onCreateSessionDescriptionError );}function gotDescription2(desc) { remoteConnection.setLocalDescription(desc); trace('Answer from remoteConnection \n' + desc.sdp); localConnection.setRemoteDescription(desc);}function iceCallback1(event) { trace('local ice callback'); if (event.candidate) { remoteConnection.addIceCandidate( event.candidate ).then( onAddIceCandidateSuccess, onAddIceCandidateError ); trace('Local ICE candidate: \n' + event.candidate.candidate); }}function iceCallback2(event) { trace('remote ice callback'); if (event.candidate) { localConnection.addIceCandidate( event.candidate ).then( onAddIceCandidateSuccess, onAddIceCandidateError ); trace('Remote ICE candidate: \n ' + event.candidate.candidate); }}function onAddIceCandidateSuccess() { trace('AddIceCandidate success.');}function onAddIceCandidateError(error) { trace('Failed to add Ice Candidate: ' + error.toString());}function receiveChannelCallback(event) { trace('Receive Channel Callback'); receiveChannel = event.channel; receiveChannel.onmessage = onReceiveMessageCallback; receiveChannel.onopen = onReceiveChannelStateChange; receiveChannel.onclose = onReceiveChannelStateChange;}function onReceiveMessageCallback(event) { trace('Received Message'); dataChannelReceive.value = event.data;}function onSendChannelStateChange() { var readyState = sendChannel.readyState; trace('Send channel state is: ' + readyState); if (readyState === 'open') { dataChannelSend.disabled = false; dataChannelSend.focus(); sendButton.disabled = false; closeButton.disabled = false; } else { dataChannelSend.disabled = true; sendButton.disabled = true; closeButton.disabled = true; }}function onReceiveChannelStateChange() { var readyState = receiveChannel.readyState; trace('Receive channel state is: ' + readyState);}function trace(text) { if (text[text.length - 1] === '\n') { text = text.substring(0, text.length - 1); } if (window.performance) { var now = (window.performance.now() / 1000).toFixed(3); console.log(now + ': ' + text); } else { console.log(text); }}
上面一段代码是可以运行的,不过大意义没有,他无法产品化,接下去的第三课,我们会大刀去修改他,让他真正实用起来,读者可以先研究以下这一段示例代码。
后面我们会使用rtp协议和信令服务继续改写,让他实用并且产品化。转载地址:http://ylbc.baihongyu.com/