JSFiddle - React, Tailwind, and code Playground

by ibcaliax

JavaScript

let micTrack;
let webcamTrack;
let pc;
let micTransceiver;
let webcamTransceiver;

navigator.mediaDevices.getUserMedia({ audio: true, video: true })
	.then((stream) =>
	{
		micTrack = stream.getAudioTracks()[0];
		webcamTrack = stream.getVideoTracks()[0];
	})
	.then(() =>
	{
		pc = new RTCPeerConnection(
			{
				iceServers    : [],
				bundlePolicy  : 'max-bundle',
				rtcpMuxPolicy : 'require',
				sdpSemantics  : 'unified-plan'
			});

		console.warn('pc: adding mic track');

		micTransceiver =
			pc.addTransceiver(micTrack, { direction: 'sendonly' });
	})
	.then(() => doSdpStuff())
	.then(() =>
	{
		console.warn('pc: removing mic track');

		micTrack.stop();

		pc.removeTrack(micTransceiver.sender);

		// NOTE: Chrome does not implement transceive.stop().
		try { micTransceiver.stop(); } catch(error) {}

		// NOTE: Safari 12.1 does not allow setting transceiver.direction.
		try { micTransceiver.direction = 'inactive'; } catch(error) {}
	})
	.then(() =>
	{
		// Add the webcam track to pc.

		console.warn('pc: adding webcam');

		webcamTransceiver =
			pc.addTransceiver(webcamTrack, { direction: 'sendonly' });
	})
	.then(() => doSdpStuff())
	.catch((error) =>
	{
		console.error(error);
	});

function doSdpStuff()
{
	let errored = false;

	return Promise.resolve()
		.then(() => pc.createOffer())
		.catch((error) =>
		{
			console.error('pc.createOffer() failed');

			errored = true;
			throw error;
		})
		.then((offer) =>
		{
			console.warn('pc.createOffer() succeeded:\n%s', offer.sdp);

			return pc.setLocalDescription(offer);
		})
		.catch((error) =>
		{
			if (errored)
				throw error;

			console.error('pc.setLocalDescription() failed');

			errored = true;
			throw error;
		})
}