webrtc官方的代码示例:
/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ /* global TimelineDataSeries, TimelineGraphView */ ‘use strict‘; const remoteVideo = document.querySelector(‘video#remoteVideo‘); const localVideo = document.querySelector(‘video#localVideo‘); const callButton = document.querySelector(‘button#callButton‘); const hangupButton = document.querySelector(‘button#hangupButton‘); const bandwidthSelector = document.querySelector(‘select#bandwidth‘); hangupButton.disabled = true; callButton.onclick = call; hangupButton.onclick = hangup; let pc1; let pc2; let localStream; // Can be set in the console before making a call to test this keeps // within the envelope set by the SDP. In kbps. const maxBandwidth = 0; let bitrateGraph; let bitrateSeries; let packetGraph; let packetSeries; let lastResult; const offerOptions = { offerToReceiveAudio: 0, offerToReceiveVideo: 1 }; function gotStream(stream) { hangupButton.disabled = false; console.log(‘Received local stream‘); localStream = stream; localVideo.srcObject = stream; localStream.getTracks().forEach(track => pc1.addTrack(track, localStream)); console.log(‘Adding Local Stream to peer connection‘); pc1.createOffer( offerOptions ).then( gotDescription1, onCreateSessionDescriptionError ); bitrateSeries = new TimelineDataSeries(); bitrateGraph = new TimelineGraphView(‘bitrateGraph‘, ‘bitrateCanvas‘); bitrateGraph.updateEndDate(); packetSeries = new TimelineDataSeries(); packetGraph = new TimelineGraphView(‘packetGraph‘, ‘packetCanvas‘); packetGraph.updateEndDate(); } function onCreateSessionDescriptionError(error) { console.log(‘Failed to create session description: ‘ + error.toString()); } function call() { callButton.disabled = true; bandwidthSelector.disabled = false; console.log(‘Starting call‘); const servers = null; pc1 = new RTCPeerConnection(servers); console.log(‘Created local peer connection object pc1‘); pc1.onicecandidate = onIceCandidate.bind(pc1); pc2 = new RTCPeerConnection(servers); console.log(‘Created remote peer connection object pc2‘); pc2.onicecandidate = onIceCandidate.bind(pc2); pc2.ontrack = gotRemoteStream; console.log(‘Requesting local stream‘); navigator.mediaDevices.getUserMedia({video: true}) .then(gotStream) .catch(e => alert(‘getUserMedia() error: ‘ + e.name)); } function gotDescription1(desc) { console.log(‘Offer from pc1 \n‘ + desc.sdp); pc1.setLocalDescription(desc).then( () => { pc2.setRemoteDescription(desc) .then(() => pc2.createAnswer().then(gotDescription2, onCreateSessionDescriptionError), onSetSessionDescriptionError); }, onSetSessionDescriptionError ); } function gotDescription2(desc) { pc2.setLocalDescription(desc).then( () => { console.log(‘Answer from pc2 \n‘ + desc.sdp); let p; if (maxBandwidth) { p = pc1.setRemoteDescription({ type: desc.type, sdp: updateBandwidthRestriction(desc.sdp, maxBandwidth) }); } else { p = pc1.setRemoteDescription(desc); } p.then(() => {}, onSetSessionDescriptionError); }, onSetSessionDescriptionError ); } function hangup() { console.log(‘Ending call‘); localStream.getTracks().forEach(track => track.stop()); pc1.close(); pc2.close(); pc1 = null; pc2 = null; hangupButton.disabled = true; callButton.disabled = false; bandwidthSelector.disabled = true; } function gotRemoteStream(e) { if (remoteVideo.srcObject !== e.streams[0]) { remoteVideo.srcObject = e.streams[0]; console.log(‘Received remote stream‘); } } function getOtherPc(pc) { return pc === pc1 ? pc2 : pc1; } function getName(pc) { return pc === pc1 ? ‘pc1‘ : ‘pc2‘; } function onIceCandidate(event) { getOtherPc(this) .addIceCandidate(event.candidate) .then(onAddIceCandidateSuccess) .catch(onAddIceCandidateError); console.log(`${getName(this)} ICE candidate:\n${event.candidate ? event.candidate.candidate : ‘(null)‘}`); } function onAddIceCandidateSuccess() { console.log(‘AddIceCandidate success.‘); } function onAddIceCandidateError(error) { console.log(‘Failed to add ICE Candidate: ‘ + error.toString()); } function onSetSessionDescriptionError(error) { console.log(‘Failed to set session description: ‘ + error.toString()); } // renegotiate bandwidth on the fly. bandwidthSelector.onchange = () => { bandwidthSelector.disabled = true; const bandwidth = bandwidthSelector.options[bandwidthSelector.selectedIndex].value; // In Chrome, use RTCRtpSender.setParameters to change bandwidth without // (local) renegotiation. Note that this will be within the envelope of // the initial maximum bandwidth negotiated via SDP. //在chrome中,使用RTCRtpSender.setParameters方法来改变带宽而不使用(本地)重新协商, //注意,这个带宽大小只能在最初的媒体协商的最大带宽之内。 if ((adapter.browserDetails.browser === ‘chrome‘ || (adapter.browserDetails.browser === ‘firefox‘ && adapter.browserDetails.version >= 64)) && ‘RTCRtpSender‘ in window && ‘setParameters‘ in window.RTCRtpSender.prototype) { const sender = pc1.getSenders()[0]; const parameters = sender.getParameters(); if (!parameters.encodings) { parameters.encodings = [{}]; } if (bandwidth === ‘unlimited‘) { delete parameters.encodings[0].maxBitrate; } else { parameters.encodings[0].maxBitrate = bandwidth * 1000; } sender.setParameters(parameters) .then(() => { bandwidthSelector.disabled = false; }) .catch(e => console.error(e)); return; } // Fallback to the SDP munging with local renegotiation way of limiting the bandwidth. //回退到SDP,用本地重新协商的方式限制带宽。 console.log("Fallback to the SDP munging with local renegotiation way of limiting"); pc1.createOffer() .then(offer => pc1.setLocalDescription(offer)) .then(() => { const desc = { type: pc1.remoteDescription.type, sdp: bandwidth === ‘unlimited‘ ? removeBandwidthRestriction(pc1.remoteDescription.sdp) : updateBandwidthRestriction(pc1.remoteDescription.sdp, bandwidth) }; console.log(‘Applying bandwidth restriction to setRemoteDescription:\n‘ + desc.sdp); return pc1.setRemoteDescription(desc); }) .then(() => { bandwidthSelector.disabled = false; }) .catch(onSetSessionDescriptionError); }; function updateBandwidthRestriction(sdp, bandwidth) { let modifier = ‘AS‘; if (adapter.browserDetails.browser === ‘firefox‘) { //>>>无符号右移,大于0的数值位运算后结果不变,任何非数值变量做此运算都会变为0 bandwidth = (bandwidth >>> 0) * 1000; modifier = ‘TIAS‘; } if (sdp.indexOf(‘b=‘ + modifier + ‘:‘) === -1) { // insert b= after c= line. sdp = sdp.replace(/c=IN (.*)\r\n/, ‘c=IN $1\r\nb=‘ + modifier + ‘:‘ + bandwidth + ‘\r\n‘); } else { sdp = sdp.replace(new RegExp(‘b=‘ + modifier + ‘:.*\r\n‘), ‘b=‘ + modifier + ‘:‘ + bandwidth + ‘\r\n‘); } return sdp; } function removeBandwidthRestriction(sdp) { return sdp.replace(/b=AS:.*\r\n/, ‘‘).replace(/b=TIAS:.*\r\n/, ‘‘); } // query getStats every second //每秒获取Senders状态 window.setInterval(() => { if (!pc1) { return; } const sender = pc1.getSenders()[0]; if (!sender) { return; } sender.getStats().then(res => { res.forEach(report => { let bytes; let packets; if (report.type === ‘outbound-rtp‘) { if (report.isRemote) { return; } const now = report.timestamp; bytes = report.bytesSent; packets = report.packetsSent; if (lastResult && lastResult.has(report.id)) { // calculate bitrate const bitrate = 8 * (bytes - lastResult.get(report.id).bytesSent) / (now - lastResult.get(report.id).timestamp); // append to chart bitrateSeries.addPoint(now, bitrate); bitrateGraph.setDataSeries([bitrateSeries]); bitrateGraph.updateEndDate(); // calculate number of packets and append to chart packetSeries.addPoint(now, packets - lastResult.get(report.id).packetsSent); packetGraph.setDataSeries([packetSeries]); packetGraph.updateEndDate(); } } }); lastResult = res; }); }, 1000);
原文:https://www.cnblogs.com/dch0/p/12197866.html