Skip to content

Instantly share code, notes, and snippets.

@gtk2k
Created August 1, 2018 14:07
Show Gist options
  • Select an option

  • Save gtk2k/9b41ef9d7c00888ecb25f90fa5e739a1 to your computer and use it in GitHub Desktop.

Select an option

Save gtk2k/9b41ef9d7c00888ecb25f90fa5e739a1 to your computer and use it in GitHub Desktop.
Chromeのサイマルキャストes6
const series = {};
const graphs = {};
const dataTypes = ['bytesSent', 'framesEncoded'];
let lastSendResult;
let lastRecvResult;
function show(stream, side) {
const id = side !== 'local' ? stream.id : 'local';
const container = document.createElement('div');
container.id = `${id}Container`;
window[side].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);
dataTypes.forEach(dataType => {
const cnv = document.createElement('canvas');
cnv.id = `${id}${dataType}Canvas`;
cnv.title = dataType;
container.appendChild(cnv);
series[dataType] = series[dataType] || {};
graphs[dataType] = graphs[dataType] || {};
series[dataType][id] = new TimelineDataSeries();
graphs[dataType][id] = new TimelineGraphView(`${id}Container`, `${id}${dataType}Canvas`);
graphs[dataType][id].updateEndDate();
});
}
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
pc1.onicecandidate = evt => pc2.addIceCandidate(evt.candidate);
pc2.onicecandidate = evt => pc1.addIceCandidate(evt.candidate);
pc2.ontrack = evt => show(evt.streams[0], 'remotes');
async function getStats(pc) {
const res = pc.getStats(null);
res.filter(report => report.type === 'outbound-rtp').forEach(report => {
const now = report.timestamp;
['bytesSent', 'framesEncoded'].forEach(dataType => {
if (!lastSendResult) return;
const data = report[dataType];
const sentResult = lastSendResult.get(report.id);
const sentResultData = sentResult[dataType];
const timestamp = sentResult.timestamp;
const calcData = { bytesSent: 8000, framesEncoded: 1000 }[dataType] * (data - sendResultData / (now - timestamp));
series[dataType][id].local.addPoint(now, calcData);
graphs[dataType][id].local.setDataSeries([graphs[dataType][id].local]);
graphs[dataType][id].local.updateEndDate();
});
});
lastSendResult = res;
}
(async _ => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: { width: 1280, height: 720 } });
pc1.addTrack(stream.getVideoTracks()[0], stream);
show(stream, false);
const offer = await pc1.createOffer();
const videoPart = SDPUtils.getMediaSections(offer.sdp)[0];
const match = videoPart.match(/a=ssrc:(\d+) cname:(.*)\r\n/);
const msid = videoPart.match(/a=ssrc:(\d+) msid:(.*)\r\n/);
const lines = offer.sdp.trim().split('\r\n');
const removed = lines.splice(lines.length - 4, 4);
const videoSSRC1 = +match[1];
const rtxSSRC1 = SDPUtils.matchPrefix(videoPart, 'a=ssrc-group:FID ')[0].split(' ')[2];
const videoSSRC2 = videoSSRC1 + 1;
const rtxSSRC2 = videoSSRC1 + 2;
const videoSSRC3 = videoSSRC1 + 3;
const rtxSSRC3 = videoSSRC1 + 4;
offer.sdp = `${[
removed[0],
removed[1],
`a=ssrc:${videoSSRC2} cname:${match[2]}`,
`a=ssrc:${videoSSRC2} msid:${msid[2]}`,
`a=ssrc:${rtxSSRC2} cname:${match[2]}`,
`a=ssrc:${rtxSSRC2} msid:${msid[2]}`,
`a=ssrc:${videoSSRC3} cname:${match[2]}`,
`a=ssrc:${videoSSRC3} msid:${msid[2]}`,
`a=ssrc:${rtxSSRC3} cname:${match[2]}`,
`a=ssrc:${rtxSSRC3} msid:${msid[2]}`,
`a=ssrc-group:FID ${videoSSRC2} ${rtxSSRC2}`,
`a=ssrc-group:FID ${videoSSRC3} ${rtxSSRC3}`,
`a=ssrc-group:SIM ${videoSSRC1} ${videoSSRC2} ${videoSSRC3}`
].join('\r\n')}\r\n`;
const offer2 = {
type: 'offer',
sdp: offer.sdp
.replace(`a=ssrc-group:SIM ${videoSSRC1} ${videoSSRC2} ${videoSSRC3}\r\n`, '')
.replace(`a=ssrc:${videoSSRC1} msid:${msid[2]}`, `a=ssrc:${videoSSRC1} msid:low low`)
.replace(`a=ssrc:${rtxSSRC1} msid:${msid[2]}`, `a=ssrc:${rtxSSRC1} msid:low low`)
.replace(`a=ssrc:${videoSSRC2} msid:${msid[2]}`, `a=ssrc:${videoSSRC2} msid:mid mid`)
.replace(`a=ssrc:${rtxSSRC2} msid:${msid[2]}`, `a=ssrc:${rtxSSRC2} msid:mid mid`)
.replace(`a=ssrc:${videoSSRC3} msid:${msid[2]}`, `a=ssrc:${videoSSRC3} msid:hi hi`)
.replace(`a=ssrc:${rtxSSRC3} msid:${msid[2]}`, `a=ssrc:${rtxSSRC3} msid:hi hi`)
};
await pc1.setLocalDescription(offer);
await pc2.setRemoteDescription(offer2);
const answer = await pc2.createAnswer();
await pc2.setLocalDescription(answer);
await pc1.setRemoteDescription(answer);
window.setInterval(_ => [pc1, pc2].forEach(pc => getStats(pc)), 2000);
} catch (err) {
console.error(err);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment