You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

352 lines
8.1 KiB

import domready from 'domready';
import UrlParse from 'url-parse';
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import {
applyMiddleware as applyReduxMiddleware,
createStore as createReduxStore
} from 'redux';
import thunk from 'redux-thunk';
// import { createLogger as createReduxLogger } from 'redux-logger';
import randomString from 'random-string';
import * as faceapi from 'face-api.js';
import Logger from './Logger';
import * as utils from './utils';
import randomName from './randomName';
import deviceInfo from './deviceInfo';
import RoomClient from './RoomClient';
import RoomContext from './RoomContext';
import * as cookiesManager from './cookiesManager';
import * as stateActions from './redux/stateActions';
import reducers from './redux/reducers';
import Room from './components/Room';
const logger = new Logger();
const reduxMiddlewares = [ thunk ];
// if (process.env.NODE_ENV === 'development')
// {
// const reduxLogger = createReduxLogger(
// {
// duration : true,
// timestamp : false,
// level : 'log',
// logErrors : true
// });
// reduxMiddlewares.push(reduxLogger);
// }
let roomClient;
const store = createReduxStore(
reducers,
undefined,
applyReduxMiddleware(...reduxMiddlewares)
);
window.STORE = store;
RoomClient.init({ store });
domready(async () =>
{
logger.debug('DOM ready');
await utils.initialize();
run();
});
async function run()
{
logger.debug('run() [environment:%s]', process.env.NODE_ENV);
const urlParser = new UrlParse(window.location.href, true);
const peerId = randomString({ length: 8 }).toLowerCase();
let roomId = urlParser.query.roomId;
let displayName =
urlParser.query.displayName || (cookiesManager.getUser() || {}).displayName;
const handlerName = urlParser.query.handlerName || urlParser.query.handler;
const forceTcp = urlParser.query.forceTcp === 'true';
const produce = urlParser.query.produce !== 'false';
const consume = urlParser.query.consume !== 'false';
const datachannel = urlParser.query.datachannel !== 'false';
const forceVP8 = urlParser.query.forceVP8 === 'true';
const forceH264 = urlParser.query.forceH264 === 'true';
const forceVP9 = urlParser.query.forceVP9 === 'true';
const enableWebcamLayers = urlParser.query.enableWebcamLayers !== 'false';
const enableSharingLayers = urlParser.query.enableSharingLayers !== 'false';
const webcamScalabilityMode = urlParser.query.webcamScalabilityMode;
const sharingScalabilityMode = urlParser.query.sharingScalabilityMode;
const numSimulcastStreams = urlParser.query.numSimulcastStreams ?
Number(urlParser.query.numSimulcastStreams) : 3;
const info = urlParser.query.info === 'true';
const faceDetection = urlParser.query.faceDetection === 'true';
const externalVideo = urlParser.query.externalVideo === 'true';
const throttleSecret = urlParser.query.throttleSecret;
const e2eKey = urlParser.query.e2eKey;
const consumerReplicas = urlParser.query.consumerReplicas;
// Enable face detection on demand.
if (faceDetection)
await faceapi.loadTinyFaceDetectorModel('/resources/face-detector-models');
if (info)
{
// eslint-disable-next-line require-atomic-updates
window.SHOW_INFO = true;
}
if (throttleSecret)
{
// eslint-disable-next-line require-atomic-updates
window.NETWORK_THROTTLE_SECRET = throttleSecret;
}
if (!roomId)
{
roomId = randomString({ length: 8 }).toLowerCase();
urlParser.query.roomId = roomId;
window.history.pushState('', '', urlParser.toString());
}
// Get the effective/shareable Room URL.
const roomUrlParser = new UrlParse(window.location.href, true);
for (const key of Object.keys(roomUrlParser.query))
{
// Don't keep some custom params.
switch (key)
{
case 'roomId':
case 'handlerName':
case 'handler':
case 'forceTcp':
case 'produce':
case 'consume':
case 'datachannel':
case 'forceVP8':
case 'forceH264':
case 'forceVP9':
case 'enableWebcamLayers':
case 'enableSharingLayers':
case 'webcamScalabilityMode':
case 'sharingScalabilityMode':
case 'numSimulcastStreams':
case 'info':
case 'faceDetection':
case 'externalVideo':
case 'throttleSecret':
case 'e2eKey':
case 'consumerReplicas':
{
break;
}
default:
{
delete roomUrlParser.query[key];
}
}
}
delete roomUrlParser.hash;
const roomUrl = roomUrlParser.toString();
let displayNameSet;
// If displayName was provided via URL or Cookie, we are done.
if (displayName)
{
displayNameSet = true;
}
// Otherwise pick a random name and mark as "not set".
else
{
displayNameSet = false;
displayName = randomName();
}
// Get current device info.
const device = deviceInfo();
store.dispatch(
stateActions.setRoomUrl(roomUrl));
store.dispatch(
stateActions.setRoomFaceDetection(faceDetection));
store.dispatch(
stateActions.setMe({ peerId, displayName, displayNameSet, device }));
roomClient = new RoomClient(
{
roomId,
peerId,
displayName,
device,
handlerName : handlerName,
forceTcp,
produce,
consume,
datachannel,
forceVP8,
forceH264,
forceVP9,
enableWebcamLayers,
enableSharingLayers,
webcamScalabilityMode,
sharingScalabilityMode,
numSimulcastStreams,
externalVideo,
e2eKey,
consumerReplicas
});
// NOTE: For debugging.
// eslint-disable-next-line require-atomic-updates
window.CLIENT = roomClient;
// eslint-disable-next-line require-atomic-updates
window.CC = roomClient;
render(
<Provider store={store}>
<RoomContext.Provider value={roomClient}>
<Room />
</RoomContext.Provider>
</Provider>,
document.getElementById('mediasoup-demo-app-container')
);
}
// NOTE: Debugging stuff.
window.__sendSdps = function()
{
logger.warn('>>> send transport local SDP offer:');
logger.warn(
roomClient._sendTransport._handler._pc.localDescription.sdp);
logger.warn('>>> send transport remote SDP answer:');
logger.warn(
roomClient._sendTransport._handler._pc.remoteDescription.sdp);
};
window.__recvSdps = function()
{
logger.warn('>>> recv transport remote SDP offer:');
logger.warn(
roomClient._recvTransport._handler._pc.remoteDescription.sdp);
logger.warn('>>> recv transport local SDP answer:');
logger.warn(
roomClient._recvTransport._handler._pc.localDescription.sdp);
};
let dataChannelTestInterval = null;
window.__startDataChannelTest = function()
{
let number = 0;
const buffer = new ArrayBuffer(32);
const view = new DataView(buffer);
dataChannelTestInterval = window.setInterval(() =>
{
if (window.DP)
{
view.setUint32(0, number++);
roomClient.sendChatMessage(buffer);
}
}, 100);
};
window.__stopDataChannelTest = function()
{
window.clearInterval(dataChannelTestInterval);
const buffer = new ArrayBuffer(32);
const view = new DataView(buffer);
if (window.DP)
{
view.setUint32(0, Math.pow(2, 32) - 1);
window.DP.send(buffer);
}
};
window.__testSctp = async function({ timeout = 100, bot = false } = {})
{
let dp;
if (!bot)
{
await window.CLIENT.enableChatDataProducer();
dp = window.CLIENT._chatDataProducer;
}
else
{
await window.CLIENT.enableBotDataProducer();
dp = window.CLIENT._botDataProducer;
}
logger.warn(
'<<< testSctp: DataProducer created [bot:%s, streamId:%d, readyState:%s]',
bot ? 'true' : 'false',
dp.sctpStreamParameters.streamId,
dp.readyState);
function send()
{
dp.send(`I am streamId ${dp.sctpStreamParameters.streamId}`);
}
if (dp.readyState === 'open')
{
send();
}
else
{
dp.on('open', () =>
{
logger.warn(
'<<< testSctp: DataChannel open [streamId:%d]',
dp.sctpStreamParameters.streamId);
send();
});
}
setTimeout(() => window.__testSctp({ timeout, bot }), timeout);
};
setInterval(() =>
{
if (window.CLIENT._sendTransport)
{
window.H1 = window.CLIENT._sendTransport._handler;
window.PC1 = window.CLIENT._sendTransport._handler._pc;
window.DP = window.CLIENT._chatDataProducer;
}
else
{
delete window.PC1;
delete window.DP;
}
if (window.CLIENT._recvTransport)
{
window.H2 = window.CLIENT._recvTransport._handler;
window.PC2 = window.CLIENT._recvTransport._handler._pc;
}
else
{
delete window.PC2;
}
}, 2000);