JSFiddle - React, Tailwind, and code Playground

JavaScript

var pc1 = new RTCPeerConnection(null);
var pc2 = new RTCPeerConnection(null);

pc1.onicecandidate = function(event) {
    if (event.candidate) { pc2.addIceCandidate(event.candidate); }
};
pc2.onicecandidate = function(event) {
    if (event.candidate) { pc1.addIceCandidate(event.candidate); }
};

function forceH264(descriptor) {
    descriptor.sdp = descriptor.sdp.replace(/(m=video.*) 120 126 97\r\n/,'$1 126\r\n');
}

function patchMaxMpbs(descriptor) {
    descriptor.sdp = descriptor.sdp.replace(/(a=fmtp:126.*)\r\n/, '$1;max-mbps=3600\r\n');
}

var mediaStream;

navigator.mediaDevices.getUserMedia({audio:true, video: true, fake: true})
.then(function(stream) {
    mediaStream = stream;
    pc1.addTrack(stream.getAudioTracks()[0], stream);
    pc1.addTrack(stream.getVideoTracks()[0], stream);
    pc2.addTrack(stream.getAudioTracks()[0], stream);
    pc2.addTrack(stream.getVideoTracks()[0], stream);
}).then(function() {
    return pc1.createOffer();
}).then(function(offer) {
    return Promise.all([offer, pc1.setLocalDescription(offer)]);
}).then(function(values) {
    var offer = values[0];
    forceH264(offer);
    return pc2.setRemoteDescription(offer);
}).then(function() {
    return pc2.createAnswer();
}).then(function(answer) {
    return Promise.all([answer, pc2.setLocalDescription(answer)]);
}).then(function(values) {
    var answer = values[0];
    patchMaxMpbs(answer);
    return pc1.setRemoteDescription(answer);
}).then(function() {
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, 4000);
    });
}).then(function() {
    pc1.removeTrack(pc1.getSenders()[1]);
    return pc1.createOffer({ offerToReceiveVideo: true });
}).then(function(offer) {
    return Promise.all([offer, pc1.setLocalDescription(offer)]);
}).then(function(values) {
    var offer = values[0];
    forceH264(offer);
    return pc2.setRemoteDescription(offer);
}).then(function() {
    return pc2.createAnswer();
}).then(function(answer) {
    return...