688 lines
18 KiB
JavaScript
Executable File
688 lines
18 KiB
JavaScript
Executable File
|
|
$.each(['me','us','we','them'],function(i,v) {
|
|
window[v] = {
|
|
'aud': {},
|
|
'in': {},
|
|
'rec': {},
|
|
'src': {},
|
|
'analyzer': {},
|
|
'osc': {},
|
|
'buffer': {},
|
|
'data': {},
|
|
'ctx': {},
|
|
'mix': {},
|
|
'pc': {},
|
|
'out': {},
|
|
'timestamp': {},
|
|
'id': {},
|
|
'type': {},
|
|
'uuid': {},
|
|
'app': {}
|
|
};
|
|
});
|
|
|
|
|
|
async function jpCanvas(app) {
|
|
var whiteboard = document.getElementById('whiteboard');
|
|
var apper = $('.wind')[$('.wind').length - 1];
|
|
app = ($(apper).attr('app') || $('#search').val());
|
|
var wb = $(whiteboard);
|
|
if (wb.attr('status') == 'recording') {
|
|
wb.attr('status', 'stopped');
|
|
jpStop(app,'marker');
|
|
}
|
|
else {
|
|
wb.attr('status', 'recording');
|
|
var timestamp = Date.now();
|
|
var marker = markerInfoGrabber();
|
|
var formData = new FormData();
|
|
var type = 'video';
|
|
formData.delete('timestamp');
|
|
formData.append('timestamp', timestamp);
|
|
|
|
formData.delete('app');
|
|
formData.append('app', app);
|
|
we['in'][app] = whiteboard.captureStream(marker['flipbook_interval']);
|
|
we['rec'][app] = new MediaRecorder(we['in'][app]);
|
|
we['timestamp'][app] = Date.now();
|
|
console.log(we);
|
|
we['rec'][app].start();
|
|
$('#marker_record').attr('src', '/images/make believe/stop.png');
|
|
$('#marker_pause').attr('app', app);
|
|
$('#marker_pause').show();
|
|
we['rec'][app].ondataavailable = (event) => {
|
|
var data = event.data;
|
|
data.type = 'track';
|
|
var ext = 'webm';
|
|
if (type == 'audio') {
|
|
ext = 'weba';
|
|
}
|
|
var formData = new FormData();
|
|
var duration = (Date.now() - we['timestamp'][app]) * -1;
|
|
formData.append('app', app);
|
|
formData.append('duration', duration);
|
|
formData.append('timestamp', timestamp);
|
|
formData.append('type', type);
|
|
formData.append('blob', data, app + '.' + ext);
|
|
|
|
$('#marker_record').attr('src', '/images/make believe/record.png');
|
|
$('#marker_pause').hide();
|
|
$('#marker_pause').removeAttr('app');
|
|
$.ajax({
|
|
url: '/manager/upload_file',
|
|
type: 'POST',
|
|
data: formData,
|
|
success: function (response) {
|
|
continent_record({'uuid':response['uuid'], 'app':response['app'],'timestamp':response['timestamp']});
|
|
},
|
|
cache: false,
|
|
contentType: false,
|
|
processData: false
|
|
});
|
|
};
|
|
}
|
|
};
|
|
|
|
async function jpStart(app,pref,uuid) {
|
|
var timestamp = Date.now();
|
|
var type = 'video';
|
|
var id = app + '_cam';
|
|
console.log(id + ' ' + type + ' ' + uuid);
|
|
me['id'][app] = id;
|
|
me['type'][app] = type;
|
|
me['uuid'][app] = uuid;
|
|
me['app'][app] = app;
|
|
if (!me[app]) {
|
|
var constraints = await constraintMaker(pref);
|
|
console.log(constraints);
|
|
if (pref == 'audio') {
|
|
constraints['video'] = false;
|
|
id = app + '_snd';
|
|
}
|
|
if (app) {
|
|
try {
|
|
me['id'][app] = id;
|
|
me['type'][app] = type;
|
|
me['uuid'][app] = uuid;
|
|
if (!me['in'][app]) {
|
|
me['in'][app] = await navigator.mediaDevices.getUserMedia(constraints);
|
|
|
|
}
|
|
if (!me['rec'][app] || me['rec'][app].state == "inactive" ) {
|
|
me['rec'][app] = new MediaRecorder(me['in'][app]);
|
|
me['timestamp'][app] = Date.now();
|
|
me['rec'][app].start();
|
|
}
|
|
me['rec'][app].ondataavailable = (event) => {
|
|
|
|
var data = event.data;
|
|
data.type = 'track';
|
|
var json = JSON.stringify(data);
|
|
var formData = new FormData();
|
|
var duration = (Date.now() - me['timestamp'][app]) * -1;
|
|
formData.append('app', app);
|
|
formData.append('duration', duration);
|
|
formData.append('timestamp', me['timestamp'][app]);
|
|
formData.append('type', type);
|
|
formData.append('blob', data, app + '.webm');
|
|
formData.append('uuid', uuid);
|
|
$.ajax({
|
|
url: '/manager/upload_file',
|
|
type: 'POST',
|
|
data: formData,
|
|
success: function (response) {
|
|
continent_record({'uuid':response['uuid'], 'app':response['app'],'timestamp':response['timestamp']});
|
|
},
|
|
cache: false,
|
|
contentType: false,
|
|
processData: false
|
|
});
|
|
|
|
};
|
|
|
|
me['rec'][app].onstop = function(event) {
|
|
console.log('Recorder stopped for ' + app);
|
|
if (pref == 'video') {
|
|
$('#' + id).remove();
|
|
$('.appointment[app="' + app + '"]').find('.media_out.vid').html('');
|
|
}
|
|
else {
|
|
$('#' + id).hide();
|
|
}
|
|
};
|
|
var app_vid_html = $('#' + app + '_cam').parent().html();
|
|
console.log(app_vid_html);
|
|
if (pref == 'audio') {
|
|
$('#' + id).show();
|
|
me['out'][app] = document.getElementById(id);
|
|
me['out'][app].srcObject = me['rec'][app].stream;
|
|
me['out'][app].muted = true;
|
|
} else {
|
|
var jmiss = JSON.stringify(misses);
|
|
$.ajax({
|
|
url: '/manager/media_window',
|
|
type: 'GET',
|
|
data: { id: id, contents: app_vid_html, timestamp: timestamp, app: app + '_cam', app_name: app, misses: jmiss },
|
|
success: function(response) {
|
|
|
|
var vid = $('.appointment[app="' + app + '"]').find('.media_out.vid');
|
|
vid.html(response.html);
|
|
me['out'][app] = document.getElementById(id);
|
|
me['out'][app].srcObject = me['rec'][app].stream;
|
|
me['out'][app].muted = true;
|
|
|
|
}
|
|
});
|
|
}
|
|
|
|
me['rec'][app].onstart = function(event) {
|
|
console.log('Recorder started for ' + app);
|
|
me['aud'][app] = new Audio;
|
|
me['aud'][app].srcObject = me['in'][app];
|
|
$('#' + id).show();
|
|
jpScope(app);
|
|
|
|
};
|
|
}
|
|
catch(error) { console.log('error',error); }
|
|
}
|
|
else {
|
|
if (!me['in'][app]) {
|
|
me['in'][app] = await navigator.mediaDevices.getUserMedia(constraints);
|
|
}
|
|
jpSmooth('', me['in'][app]);
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
}
|
|
}
|
|
|
|
async function constraintMaker(pref) {
|
|
|
|
var constraints = { 'audio': false, 'video': false };
|
|
var isVideo = false;
|
|
var isInitialized = false;
|
|
var hasAudio = false;
|
|
var hasVideo = false;
|
|
var av = await navigator.mediaDevices.enumerateDevices();
|
|
console.log(av);
|
|
$.each(av, function(i,v) {
|
|
var mic = localStorage.getItem('audioinput' + v.deviceId );
|
|
var cam = localStorage.getItem('videoinput' + v.deviceId );
|
|
var spkr = localStorage.getItem('audiooutput' + v.deviceId );
|
|
if (v.kind == 'audioinput') {
|
|
console.log(v.deviceId);
|
|
|
|
hasAudio = true;
|
|
if (mic == 'on' && v.deviceId) {
|
|
isInitialized = true;
|
|
constraints['audio'] = { deviceId: { exact: v.deviceId } };
|
|
console.log('mic is on');
|
|
}
|
|
}
|
|
else if (v.kind == 'videoinput') {
|
|
hasVideo = true;
|
|
if (cam == 'on' && v.deviceId) {
|
|
|
|
isInitialized = true;
|
|
constraints['video'] = {
|
|
deviceId: {
|
|
exact: v.deviceId
|
|
},
|
|
width: { ideal: 1280, max:4000 },
|
|
height: { ideal: 720, max:3000 }
|
|
};
|
|
isVideo = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
if (isVideo == false || pref == 'audio') {
|
|
constraints['video'] = false;
|
|
|
|
// say_it('ok no vid');
|
|
}
|
|
if (isInitialized == false) {
|
|
// say_it('ok no init');
|
|
constraints = { 'video': false, 'audio': true };
|
|
if (hasVideo == true || pref != 'audio') {
|
|
constraints['video'] = true;
|
|
}
|
|
var test = await navigator.mediaDevices.getUserMedia(constraints);
|
|
test.onstart = function(event) {
|
|
test.stop();
|
|
};
|
|
}
|
|
// say_it('the end');
|
|
|
|
return constraints;
|
|
}
|
|
|
|
function jpScope(app) {
|
|
var x = 0;
|
|
var canvas = document.getElementById('visualizer_' + app);
|
|
var ctx = canvas.getContext("2d");
|
|
|
|
var sliceWidth = canvas.width / me['buffer'][app];
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
me['analyzer'][app].getByteFrequencyData(me['data'][app]);
|
|
|
|
for (var i = 0; i < me['buffer'][app]; i++) {
|
|
var v = me['data'][app][i] / 128.0;
|
|
var y = v * (canvas.height / 2);
|
|
|
|
if (i === 0) {
|
|
ctx.moveTo(x, y);
|
|
} else {
|
|
ctx.lineTo(x, y);
|
|
}
|
|
x += sliceWidth;
|
|
}
|
|
ctx.stroke();
|
|
//console.log(frequency);
|
|
//requestAnimationFrame(jpScope(app));
|
|
|
|
}
|
|
|
|
async function jpScreen(app,uuid) {
|
|
var id = app + '_scr';
|
|
var timestamp = Date.now();
|
|
var type = 'screen';
|
|
me['id'][app] = id;
|
|
me['type'][app] = type;
|
|
me['uuid'][app] = uuid;
|
|
me['app'][app] = app;
|
|
try {
|
|
if (app) {
|
|
|
|
if (!us['in'][app]) {
|
|
var options = { 'surfaceSwitching': 'include', 'audio': true, 'video': { 'displaySurface': 'monitor' }};
|
|
us['in'][app] = await navigator.mediaDevices.getDisplayMedia(options);
|
|
console.log(us);
|
|
}
|
|
if (!us['rec'][app] || us['rec']['app'].state =="inactive" ) {
|
|
us['rec'][app] = new MediaRecorder(us['in'][app]);
|
|
us['timestamp'][app] = Date.now();
|
|
us['rec'][app].start();
|
|
$('#' + id).show();
|
|
|
|
}
|
|
|
|
us['rec'][app].ondataavailable = (event) => {
|
|
event.data.app = app;
|
|
|
|
var data = event.data;
|
|
data.type = 'screen';
|
|
|
|
var json = JSON.stringify(data);
|
|
|
|
var formData = new FormData();
|
|
var duration = data.size;
|
|
var duration = (Date.now() - us['timestamp'][app]) * -1;
|
|
formData.append('app', app);
|
|
formData.append('duration', duration);
|
|
formData.append('timestamp', us['timestamp'][app]);
|
|
formData.append('type', 'screen');
|
|
formData.append('blob', data, app + '.webm');
|
|
formData.append('duration', duration);
|
|
formData.append('uuid', uuid);
|
|
$.ajax({
|
|
url: '/manager/upload_file',
|
|
type: 'POST',
|
|
data: formData,
|
|
success: function (response) {
|
|
continent_record({'uuid':response['uuid'], 'app':response['app'],'timestamp':response['timestamp']});
|
|
},
|
|
cache: false,
|
|
contentType: false,
|
|
processData: false
|
|
});
|
|
us['mix'][app] = data;
|
|
};
|
|
us['rec'][app].onstart = function(event) {
|
|
console.log('Recorder started for ' + app);
|
|
|
|
};
|
|
us['rec'][app].onstop = function(event) {
|
|
console.log('Recorder stopped for ' + app);
|
|
$('#' + id).remove();
|
|
$('.appointment[app="' + app + '"]').find('.media_out.scr').html('');
|
|
};
|
|
var app_vid_html = $('#' + app + '_scr').parent().html();
|
|
var jmiss = JSON.stringify(misses);
|
|
$.ajax({
|
|
url: '/manager/media_window',
|
|
type: 'GET',
|
|
data: { id:id, contents: app_vid_html, timestamp: timestamp, app: app + '_scr', app_name: app, misses: jmiss },
|
|
success: function(response) {
|
|
console.log(response);
|
|
if ($('#club_scr').length > 0) {
|
|
us['out'][app] = document.getElementById(id);
|
|
us['out'][app].srcObject = us['rec'][app].stream;
|
|
|
|
$('#' + id).css({'width': '100%' });
|
|
}
|
|
else {
|
|
var vid = $('.appointment[app="' + app + '"]').find('.media_out.scr');
|
|
vid.html(response.html);
|
|
us['out'][app] = document.getElementById(id);
|
|
us['out'][app].srcObject = us['rec'][app].stream;
|
|
}
|
|
|
|
us['out'][app].muted = true;
|
|
|
|
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
if (!us['in'][app]) {
|
|
var options = { 'surfaceSwitching': 'include', 'audio': true, 'video': { 'displaySurface': 'monitor' }};
|
|
us['in'][app] = await navigator.mediaDevices.getDisplayMedia(options);
|
|
}
|
|
jpSmooth('', us['in'][app]);
|
|
}
|
|
}
|
|
catch (error) {
|
|
|
|
}
|
|
}
|
|
|
|
function jpReport(app) {
|
|
|
|
var apps = [];
|
|
var appts = { me: [], us: [], them: [], we: [] };
|
|
$.each(appts, function(s,d) {
|
|
$.each(window[s], function(i,v) {
|
|
var seen = [];
|
|
$.each(v, function(ir,vr) {
|
|
console.log(ir);
|
|
if (app == ir) {
|
|
seen = $.grep(apps, function(irs,vrs) {
|
|
console.log(irs);
|
|
return irs['app'] == ir;
|
|
});
|
|
}
|
|
if (seen == 0) {
|
|
appts[app] = [];
|
|
appts[app].push(s);
|
|
apps.push({ app: window[s]['app'][app], in: window[s]['in'][app], perspective: s, type: window[s]['type'][app], id: window[s]['id'][app], uuid: window[s]['uuid'][app] });
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
return apps;
|
|
}
|
|
|
|
function jpRestore(app,jpR) {
|
|
var apps = [];
|
|
var appts = { me: [], us: [], them: [], we: [] };
|
|
console.log(jpR);
|
|
$.each(jpR, function(s,d) {
|
|
console.log(s);
|
|
console.log(d);
|
|
if (d['app'] == app && d['in']) {
|
|
console.log(v);
|
|
if (d['app'] == app) {
|
|
jpStart(d['app'],d['type'], d['uuid']);
|
|
}
|
|
else if ( s == 'us' ) {
|
|
jpScreen(d['app'],d['uuid']);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
|
|
function jpStop(app,imperative,uuid) {
|
|
|
|
console.log('jpStop ' + app);
|
|
if ((imperative == 'video' || imperative == 'audio') || imperative == undefined) {
|
|
try {
|
|
me['in'][app].getTracks().forEach(function(track) {
|
|
console.log(track);
|
|
track.stop();
|
|
});
|
|
me['in'][app] = undefined;
|
|
me['rec'][app].stop();
|
|
// me['rec'][app] = undefined;
|
|
me['out'][app] = undefined;
|
|
}
|
|
catch {
|
|
$.each(me['in'],function(i,v) {
|
|
console.log(i);
|
|
try {
|
|
me['rec'][i].getTracks().forEach(function(track) {
|
|
console.log(track);
|
|
track.stop();
|
|
});
|
|
}
|
|
catch {
|
|
me['in'][app] = undefined;
|
|
me['rec'][app] = undefined;
|
|
me['out'][app] = undefined;
|
|
}
|
|
});
|
|
|
|
}
|
|
}
|
|
if (imperative == 'screen' || imperative == undefined) {
|
|
try {
|
|
us['in'][app].getTracks().forEach(function(track) {
|
|
console.log(track);
|
|
track.stop();
|
|
});
|
|
us['in'][app] = undefined;
|
|
us['rec'][app].stop();
|
|
us['rec'][app] = undefined;
|
|
us['out'][app] = undefined;
|
|
}
|
|
catch {
|
|
$.each(us['in'],function(i,v) {
|
|
console.log(i);
|
|
try {
|
|
us['rec'][i].getTracks().forEach(function(track) {
|
|
console.log(track);
|
|
track.stop();
|
|
});
|
|
}
|
|
catch {
|
|
us['in'][app] = undefined;
|
|
us['rec'][app] = undefined;
|
|
us['out'][app] = undefined;
|
|
}
|
|
});
|
|
|
|
}
|
|
}
|
|
if (imperative == 'marker' || imperative == undefined) {
|
|
try {
|
|
we['in'][app].getTracks().forEach(function(track) {
|
|
console.log(track);
|
|
track.stop();
|
|
});
|
|
we['in'][app] = undefined;
|
|
we['rec'][app].stop();
|
|
we['rec'][app] = undefined;
|
|
we['out'][app] = undefined;
|
|
}
|
|
catch {
|
|
$.each(we['in'],function(i,v) {
|
|
console.log(i);
|
|
try {
|
|
we['rec'][i].getTracks().forEach(function(track) {
|
|
console.log(track);
|
|
track.stop();
|
|
});
|
|
}
|
|
catch {
|
|
we['in'][app] = undefined;
|
|
we['rec'][app] = undefined;
|
|
we['out'][app] = undefined;
|
|
}
|
|
});
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
function inputClose(app) {
|
|
var timestamp = Date.now();
|
|
console.log(app + ' is getting shut down');
|
|
me['in'][app] = null;
|
|
me['out'][app] = null;
|
|
|
|
}
|
|
|
|
function jpAppointmentWriter() {
|
|
|
|
};
|
|
|
|
function jpWatcher() {
|
|
var returner = {};
|
|
|
|
$.each(me['out'], function(i,v) {
|
|
|
|
var id = $(v).attr('id');
|
|
var video = document.getElementById(id);
|
|
if ($(video).is('video')) {
|
|
var canvas = document.createElement('canvas');
|
|
var ratio = video.videoWidth / video.videoHeight;
|
|
canvas.width = 640 || 0;
|
|
canvas.height = ratio * canvas.width || 0;
|
|
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
|
|
var image = canvas.toDataURL('image/png');
|
|
returner[i] = { 'image': image, 'ratio': ratio, 'width': canvas.width, 'height': canvas.height };
|
|
}
|
|
});
|
|
$.each(us['out'], function(i,v) {
|
|
var id = $(v).attr('id');
|
|
var video = document.getElementById(id);
|
|
if ($(video).is('video')) {
|
|
var canvas = document.createElement('canvas');
|
|
|
|
var ratio = video.videoWidth / video.videoHeight;
|
|
canvas.width = 640 || 0;
|
|
canvas.height = ratio * canvas.width || 0;
|
|
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
|
|
var image = canvas.toDataURL('image/png');
|
|
returner[i] = { 'image': image, 'ratio': ratio, 'width': canvas.width, 'height': canvas.height };
|
|
}
|
|
});
|
|
if ($('#whiteboard').is(':visible')) {
|
|
var canvas = document.getElementById('whiteboard');
|
|
var vcanvas = document.createElement('canvas');
|
|
var ratio = canvas.width / canvas.height;
|
|
vcanvas.width = 640 || 0;
|
|
vcanvas.height = ratio * vcanvas.width;
|
|
vcanvas.getContext('2d').drawImage(canvas, 0, 0, vcanvas.width, vcanvas.height);
|
|
var image = vcanvas.toDataURL('image/png');
|
|
returner['we'] = { 'image': image, 'ratio': ratio, 'width': canvas.width, 'height': canvas.height };
|
|
}
|
|
return returner;
|
|
}
|
|
|
|
|
|
let localStream;
|
|
let pc1;
|
|
let pc2;
|
|
var jpSmoothInterval;
|
|
|
|
function jpSmooth(app,sourceStream) {
|
|
pc1 = new RTCPeerConnection(servers); // eslint-disable-line new-cap
|
|
console.log('Created local peer connection object pc1');
|
|
pc1.onicecandidate = e => onIceCandidate(pc1, e);
|
|
pc2 = new RTCPeerConnection(servers); // eslint-disable-line new-cap
|
|
console.log('Created remote peer connection object pc2');
|
|
pc2.onicecandidate = e => onIceCandidate(pc2, e);
|
|
pc2.ontrack = gotRemoteStream;
|
|
sourceStream.getTracks().forEach(track => pc1.addTrack(track, sourceStream));
|
|
pc1.createOffer().then(gotDescription1).catch(error => console.log(`createOffer failed: ${error}`));
|
|
}
|
|
|
|
function jpViewAdjuster(streams) {
|
|
var container = $('#mailbox_video_container');
|
|
var videos = container.find('video');
|
|
$.each(streams, function(i,v) {
|
|
console.log(streams[i]);
|
|
var id = streams[i].id;
|
|
if ($('#' + id).length == 0) {
|
|
container.append('<video class="jpSmoothStream" id="' + id + '" mute autoplay></video>');
|
|
var audioElement = document.getElementById(id);
|
|
audioElement.muted = true;
|
|
them['in'][id] = streams[i];
|
|
audioElement.srcObject = them['in'][id];
|
|
them['pc'][id] = pc2;
|
|
videos = container.find('video');
|
|
var width = container.width();
|
|
var height = container.height();
|
|
width = numeral(container.width() / videos.length).value();
|
|
$('#' + id ).width(width);
|
|
}
|
|
});
|
|
clearInterval(jpSmoothInterval);
|
|
jpSmoothInterval = setInterval(function() {
|
|
$('.jpSmoothStream').each(function(ir,vr) {
|
|
var id = $(vr).attr('id');
|
|
var v = document.getElementById(id);
|
|
if (them['stats'][id] == v.currentTime) {
|
|
$(vr).remove();
|
|
them['pc'][id].close();
|
|
}
|
|
them['stats'][id] = v.currentTime
|
|
});
|
|
},1000);
|
|
}
|
|
|
|
function gotRemoteStream(e) {
|
|
jpViewAdjuster(e.streams);
|
|
}
|
|
|
|
function gotDescription1(desc) {
|
|
console.log(`Offer from pc1\n${desc.sdp}`);
|
|
|
|
pc1.setLocalDescription(desc);
|
|
pc2.setRemoteDescription(desc);
|
|
pc2.createAnswer()
|
|
.then(gotDescription2)
|
|
.catch(error => logError(`createAnswer failed: ${error}`));
|
|
}
|
|
|
|
function gotDescription2(desc) {
|
|
console.log(`Answer from pc2\n${desc.sdp}`);
|
|
pc2.setLocalDescription(desc);
|
|
pc1.setRemoteDescription(desc);
|
|
}
|
|
|
|
function getOtherPc(pc) {
|
|
return (pc === pc1) ? pc2 : pc1;
|
|
}
|
|
|
|
function getName(pc) {
|
|
return (pc === pc1) ? 'pc1' : 'pc2';
|
|
}
|
|
|
|
function onIceCandidate(pc, event) {
|
|
getOtherPc(pc)
|
|
.addIceCandidate(event.candidate)
|
|
.then(() => onAddIceCandidateSuccess(pc), err => onAddIceCandidateError(pc, err));
|
|
console.log(`${getName(pc)} ICE candidate:\n${event.candidate ? event.candidate.candidate : '(null)'}`);
|
|
}
|
|
|
|
function onAddIceCandidateSuccess() {
|
|
console.log('AddIceCandidate success.');
|
|
}
|
|
|
|
function onAddIceCandidateError(error) {
|
|
logError(`Failed to add Ice Candidate: ${error.toString()}`);
|
|
} |