Created
August 1, 2018 10:27
-
-
Save gtk2k/7e626948a397ef501adb30f56351ed99 to your computer and use it in GitHub Desktop.
chromeのサイマルキャスト
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script> | |
<script src="https://rawgit.com/otalk/sdp/master/sdp.js"></script> | |
<script src="https://webrtc.github.io/samples/src/js/third_party/graph.js"></script> | |
<style> | |
video { | |
width: 320px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="local"> | |
<h2>Local Video</h2> | |
</div> | |
<div id="remotes"> | |
<h2>Remote Videos</h2> | |
</div> | |
<script> | |
const bitrateSeries = {}; | |
const bitrateGraphs = {}; | |
const framerateSeries = {}; | |
const framerateGraphs = {}; | |
let lastSendResult; | |
let lastRecvResult; | |
function show(stream, isRemote) { | |
const id = isRemote ? stream.id : 'local'; | |
const container = document.createElement('div'); | |
container.id = id + 'Container'; | |
document.getElementById(isRemote ? 'remotes' : 'local').appendChild(container); | |
const v = document.createElement('video'); | |
v.autoplay = true; | |
v.srcObject = stream; | |
v.onresize = () => v.title = 'video dimensions: ' + v.videoWidth + 'x' + v.videoHeight; | |
container.appendChild(v); | |
const bitrateCanvas = document.createElement('canvas'); | |
bitrateCanvas.id = id + 'BitrateCanvas'; | |
bitrateCanvas.title = 'Bitrate'; | |
container.appendChild(bitrateCanvas); | |
const bitrateGraph = new TimelineGraphView(id + 'Container', id + 'BitrateCanvas'); | |
bitrateGraph.updateEndDate(); | |
bitrateSeries[id] = new TimelineDataSeries(); | |
bitrateGraphs[id] = bitrateGraph; | |
const framerateCanvas = document.createElement('canvas'); | |
framerateCanvas.id = id + 'FramerateCanvas'; | |
framerateCanvas.title = 'Framerate'; | |
container.appendChild(framerateCanvas); | |
const framerateGraph = new TimelineGraphView(id + 'Container', id + 'FramerateCanvas'); | |
framerateGraph.updateEndDate(); | |
framerateSeries[id] = new TimelineDataSeries(); | |
framerateGraphs[id] = framerateGraph; | |
} | |
const pc1 = new RTCPeerConnection(); | |
const pc2 = new RTCPeerConnection(); | |
pc1.onicecandidate = (e) => pc2.addIceCandidate(e.candidate); | |
pc2.onicecandidate = (e) => pc1.addIceCandidate(e.candidate); | |
pc2.ontrack = (e) => show(e.streams[0], true); | |
navigator.mediaDevices.getUserMedia({video: {width: 1280, height: 720}}) | |
.then((stream) => { | |
pc1.addTrack(stream.getVideoTracks()[0], stream); | |
show(stream, false); | |
return pc1.createOffer(); | |
}) | |
.then((offer) => { | |
var videoPart = SDPUtils.getMediaSections(offer.sdp)[0]; | |
var match = videoPart.match(/a=ssrc:(\d+) cname:(.*)\r\n/); | |
var msid = videoPart.match(/a=ssrc:(\d+) msid:(.*)\r\n/); | |
var lines = offer.sdp.trim().split('\r\n'); | |
var removed = lines.splice(lines.length - 4, 4); | |
var videoSSRC1 = parseInt(match[1]); | |
var rtxSSRC1 = SDPUtils.matchPrefix(videoPart, 'a=ssrc-group:FID ')[0].split(' ')[2]; | |
var videoSSRC2 = videoSSRC1 + 1; | |
var rtxSSRC2 = videoSSRC1 + 2; | |
var videoSSRC3 = videoSSRC1 + 3; | |
var rtxSSRC3 = videoSSRC1 + 4; | |
lines.push(removed[0]); | |
lines.push(removed[1]); | |
lines.push('a=ssrc:' + videoSSRC2 + ' cname:' + match[2]); | |
lines.push('a=ssrc:' + videoSSRC2 + ' msid:' + msid[2]); | |
lines.push('a=ssrc:' + rtxSSRC2 + ' cname:' + match[2]); | |
lines.push('a=ssrc:' + rtxSSRC2 + ' msid:' + msid[2]); | |
lines.push('a=ssrc:' + videoSSRC3 + ' cname:' + match[2]); | |
lines.push('a=ssrc:' + videoSSRC3 + ' msid:' + msid[2]); | |
lines.push('a=ssrc:' + rtxSSRC3 + ' cname:' + match[2]); | |
lines.push('a=ssrc:' + rtxSSRC3 + ' msid:' + msid[2]); | |
lines.push('a=ssrc-group:FID ' + videoSSRC2 + ' ' + rtxSSRC2); | |
lines.push('a=ssrc-group:FID ' + videoSSRC3 + ' ' + rtxSSRC3); | |
lines.push('a=ssrc-group:SIM ' + videoSSRC1 + ' ' + videoSSRC2 + ' ' + videoSSRC3); | |
offer.sdp = lines.join('\r\n') + '\r\n'; | |
var offer2 = { | |
type: 'offer', | |
sdp: offer.sdp, | |
}; | |
offer2.sdp = offer2.sdp.replace('a=ssrc-group:SIM ' + videoSSRC1 + ' ' + videoSSRC2 + ' ' + videoSSRC3 + '\r\n', ''); | |
offer2.sdp = offer2.sdp.replace('a=ssrc:' + videoSSRC1 + ' msid:' + msid[2], 'a=ssrc:' + videoSSRC1 + ' msid:low low'); | |
offer2.sdp = offer2.sdp.replace('a=ssrc:' + rtxSSRC1 + ' msid:' + msid[2], 'a=ssrc:' + rtxSSRC1 + ' msid:low low'); | |
offer2.sdp = offer2.sdp.replace('a=ssrc:' + videoSSRC2 + ' msid:' + msid[2], 'a=ssrc:' + videoSSRC2 + ' msid:mid mid'); | |
offer2.sdp = offer2.sdp.replace('a=ssrc:' + rtxSSRC2 + ' msid:' + msid[2], 'a=ssrc:' + rtxSSRC2 + ' msid:mid mid'); | |
offer2.sdp = offer2.sdp.replace('a=ssrc:' + videoSSRC3 + ' msid:' + msid[2], 'a=ssrc:' + videoSSRC3 + ' msid:hi hi'); | |
offer2.sdp = offer2.sdp.replace('a=ssrc:' + rtxSSRC3 + ' msid:' + msid[2], 'a=ssrc:' + rtxSSRC3 + ' msid:hi hi'); | |
return Promise.all([ | |
pc1.setLocalDescription(offer), | |
pc2.setRemoteDescription(offer2), | |
]); | |
}) | |
.then(() => pc2.createAnswer()) | |
.then(answer => { | |
return Promise.all([ | |
pc2.setLocalDescription(answer), | |
pc1.setRemoteDescription(answer), | |
]); | |
}) | |
.then(function() { | |
window.setInterval(() => { | |
pc1.getStats(null).then((res) => { | |
res.forEach((report) => { | |
const now = report.timestamp; | |
if (report.type === 'outbound-rtp') { | |
const bytes = report.bytesSent; | |
const frames = report.framesEncoded; | |
if (lastSendResult && lastSendResult.get(report.id)) { | |
const graphName = 'local'; | |
// calculate bitrate | |
const bitrate = 8000 * (bytes - lastSendResult.get(report.id).bytesSent) / | |
(now - lastSendResult.get(report.id).timestamp); | |
bitrateSeries[graphName].addPoint(now, bitrate); | |
bitrateGraphs[graphName].setDataSeries([bitrateSeries[graphName]]); | |
bitrateGraphs[graphName].updateEndDate(); | |
// calculate framerate. | |
const framerate = 1000 * (frames - lastSendResult.get(report.id).framesEncoded) / | |
(now - lastSendResult.get(report.id).timestamp); | |
framerateSeries[graphName].addPoint(now, framerate); | |
framerateGraphs[graphName].setDataSeries([framerateSeries[graphName]]); | |
framerateGraphs[graphName].updateEndDate(); | |
} | |
} | |
}); | |
lastSendResult = res; | |
}); | |
pc2.getStats(null).then((res) => { | |
res.forEach((report) => { | |
const now = report.timestamp; | |
if (report.type === 'inbound-rtp') { | |
const bytes = report.bytesReceived; | |
const frames = report.framesDecoded; | |
if (lastRecvResult && lastRecvResult.get(report.id)) { | |
const track = res.get(report.trackId).trackIdentifier; | |
const graphName = track; | |
// calculate bitrate | |
const bitrate = 8000 * (bytes - lastRecvResult.get(report.id).bytesReceived) / | |
(now - lastRecvResult.get(report.id).timestamp); | |
bitrateSeries[graphName].addPoint(now, bitrate); | |
bitrateGraphs[graphName].setDataSeries([bitrateSeries[graphName]]); | |
bitrateGraphs[graphName].updateEndDate(); | |
// calculate framerate. | |
const framerate = 1000 * (frames - lastRecvResult.get(report.id).framesDecoded) / | |
(now - lastRecvResult.get(report.id).timestamp); | |
framerateSeries[graphName].addPoint(now, framerate); | |
framerateGraphs[graphName].setDataSeries([framerateSeries[graphName]]); | |
framerateGraphs[graphName].updateEndDate(); | |
} | |
} | |
}); | |
lastRecvResult = res; | |
}); | |
}, 2000); | |
}) | |
.catch(e => console.error(e)); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment