Fix calling tools JS
This commit is contained in:
parent
5f0080a7d7
commit
29eb07c159
23 changed files with 27 additions and 23 deletions
263
js/calling-tools/peer_connection_update_table.js
Normal file
263
js/calling-tools/peer_connection_update_table.js
Normal file
|
@ -0,0 +1,263 @@
|
|||
// Derived from Chromium WebRTC Internals Dashboard - see Acknowledgements for full license details
|
||||
|
||||
import {$} from './util.js';
|
||||
|
||||
const MAX_NUMBER_OF_STATE_CHANGES_DISPLAYED = 10;
|
||||
const MAX_NUMBER_OF_EXPANDED_MEDIASECTIONS = 10;
|
||||
/**
|
||||
* The data of a peer connection update.
|
||||
* @param {number} pid The id of the renderer.
|
||||
* @param {number} lid The id of the peer conneciton inside a renderer.
|
||||
* @param {string} type The type of the update.
|
||||
* @param {string} value The details of the update.
|
||||
*/
|
||||
class PeerConnectionUpdateEntry {
|
||||
constructor(pid, lid, type, value) {
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.pid = pid;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.lid = lid;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
this.type = type;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maintains the peer connection update log table.
|
||||
*/
|
||||
export class PeerConnectionUpdateTable {
|
||||
constructor() {
|
||||
/**
|
||||
* @type {string}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
this.UPDATE_LOG_ID_SUFFIX_ = '-update-log';
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
this.UPDATE_LOG_CONTAINER_CLASS_ = 'update-log-container';
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
this.UPDATE_LOG_TABLE_CLASS = 'update-log-table';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the update to the update table as a new row. The type of the update
|
||||
* is set to the summary of the cell; clicking the cell will reveal or hide
|
||||
* the details as the content of a TextArea element.
|
||||
*
|
||||
* @param {!Element} peerConnectionElement The root element.
|
||||
* @param {!PeerConnectionUpdateEntry} update The update to add.
|
||||
*/
|
||||
addPeerConnectionUpdate(peerConnectionElement, update) {
|
||||
const tableElement = this.ensureUpdateContainer_(peerConnectionElement);
|
||||
|
||||
const row = document.createElement('tr');
|
||||
tableElement.firstChild.appendChild(row);
|
||||
|
||||
const time = new Date(parseFloat(update.time));
|
||||
const timeItem = document.createElement('td');
|
||||
timeItem.textContent = time.toLocaleString();
|
||||
row.appendChild(timeItem);
|
||||
|
||||
// `type` is a display variant of update.type which does not get serialized
|
||||
// into the JSON dump.
|
||||
let type = update.type;
|
||||
|
||||
if (update.value.length === 0) {
|
||||
const typeItem = document.createElement('td');
|
||||
typeItem.textContent = type;
|
||||
row.appendChild(typeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
if (update.type === 'icecandidate' || update.type === 'addIceCandidate') {
|
||||
const parts = update.value.split(', ');
|
||||
type += '(' + parts[0] + ', ' + parts[1]; // show sdpMid/sdpMLineIndex.
|
||||
const candidateParts = parts[2].substr(11).split(' ');
|
||||
if (candidateParts && candidateParts[7]) { // show candidate type.
|
||||
type += ', type: ' + candidateParts[7];
|
||||
}
|
||||
type += ')';
|
||||
} else if (
|
||||
update.type === 'createOfferOnSuccess' ||
|
||||
update.type === 'createAnswerOnSuccess') {
|
||||
this.setLastOfferAnswer_(tableElement, update);
|
||||
} else if (update.type === 'setLocalDescription') {
|
||||
const lastOfferAnswer = this.getLastOfferAnswer_(tableElement);
|
||||
if (update.value.startsWith('type: rollback')) {
|
||||
this.setLastOfferAnswer_(tableElement, {value: undefined})
|
||||
} else if (lastOfferAnswer && update.value !== lastOfferAnswer) {
|
||||
type += ' (munged)';
|
||||
}
|
||||
} else if (update.type === 'setConfiguration') {
|
||||
// Update the configuration that is displayed at the top.
|
||||
peerConnectionElement.firstChild.children[2].textContent = update.value;
|
||||
} else if (['transceiverAdded',
|
||||
'transceiverModified'].includes(update.type)) {
|
||||
// Show the transceiver index.
|
||||
const indexLine = update.value.split('\n', 3)[2];
|
||||
if (indexLine.startsWith('getTransceivers()[')) {
|
||||
type += ' ' + indexLine.substring(17, indexLine.length - 2);
|
||||
}
|
||||
const kindLine = update.value.split('\n', 5)[4].trim();
|
||||
if (kindLine.startsWith('kind:')) {
|
||||
type += ', ' + kindLine.substring(6, kindLine.length - 2);
|
||||
}
|
||||
} else if (['iceconnectionstatechange', 'connectionstatechange',
|
||||
'signalingstatechange'].includes(update.type)) {
|
||||
const fieldName = {
|
||||
'iceconnectionstatechange' : 'iceconnectionstate',
|
||||
'connectionstatechange' : 'connectionstate',
|
||||
'signalingstatechange' : 'signalingstate',
|
||||
}[update.type];
|
||||
const el = peerConnectionElement.getElementsByClassName(fieldName)[0];
|
||||
const numberOfEvents = el.textContent.split(' => ').length;
|
||||
if (numberOfEvents < MAX_NUMBER_OF_STATE_CHANGES_DISPLAYED) {
|
||||
el.textContent += ' => ' + update.value;
|
||||
} else if (numberOfEvents >= MAX_NUMBER_OF_STATE_CHANGES_DISPLAYED) {
|
||||
el.textContent += ' => ...';
|
||||
}
|
||||
}
|
||||
|
||||
const summaryItem = $('summary-template').content.cloneNode(true);
|
||||
const summary = summaryItem.querySelector('summary');
|
||||
summary.textContent = type;
|
||||
row.appendChild(summaryItem);
|
||||
|
||||
const valueContainer = document.createElement('pre');
|
||||
const details = row.cells[1].childNodes[0];
|
||||
details.appendChild(valueContainer);
|
||||
|
||||
// Highlight ICE/DTLS failures and failure callbacks.
|
||||
if ((update.type === 'iceconnectionstatechange' &&
|
||||
update.value === 'failed') ||
|
||||
(update.type === 'connectionstatechange' &&
|
||||
update.value === 'failed') ||
|
||||
update.type.indexOf('OnFailure') !== -1 ||
|
||||
update.type === 'addIceCandidateFailed') {
|
||||
valueContainer.parentElement.classList.add('update-log-failure');
|
||||
}
|
||||
|
||||
// RTCSessionDescription is serialized as 'type: <type>, sdp:'
|
||||
if (update.value.indexOf(', sdp:') !== -1) {
|
||||
const [type, sdp] = update.value.substr(6).split(', sdp: ');
|
||||
if (type === 'rollback') {
|
||||
// Rollback has no SDP.
|
||||
summary.textContent += ' (type: "rollback")';
|
||||
} else {
|
||||
// Create a copy-to-clipboard button.
|
||||
const copyBtn = document.createElement('button');
|
||||
copyBtn.textContent = 'Copy description to clipboard';
|
||||
copyBtn.onclick = () => {
|
||||
navigator.clipboard.writeText(JSON.stringify({type, sdp}));
|
||||
};
|
||||
valueContainer.appendChild(copyBtn);
|
||||
|
||||
// Fold the SDP sections.
|
||||
const sections = sdp.split('\nm=')
|
||||
.map((part, index) => (index > 0 ?
|
||||
'm=' + part : part).trim() + '\r\n');
|
||||
summary.textContent +=
|
||||
' (type: "' + type + '", ' + sections.length + ' sections)';
|
||||
sections.forEach(section => {
|
||||
const lines = section.trim().split('\n');
|
||||
// Extract the mid attribute.
|
||||
const mid = lines
|
||||
.filter(line => line.startsWith('a=mid:'))
|
||||
.map(line => line.substr(6))[0];
|
||||
const sectionDetails = document.createElement('details');
|
||||
// Fold by default for large SDP.
|
||||
sectionDetails.open =
|
||||
sections.length <= MAX_NUMBER_OF_EXPANDED_MEDIASECTIONS;
|
||||
sectionDetails.textContent = lines.slice(1).join('\n');
|
||||
|
||||
const sectionSummary = document.createElement('summary');
|
||||
sectionSummary.textContent =
|
||||
lines[0].trim() +
|
||||
' (' + (lines.length - 1) + ' more lines)' +
|
||||
(mid ? ' mid=' + mid : '');
|
||||
sectionDetails.appendChild(sectionSummary);
|
||||
|
||||
valueContainer.appendChild(sectionDetails);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
valueContainer.textContent = update.value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure the update log table of the peer connection is created.
|
||||
*
|
||||
* @param {!Element} peerConnectionElement The root element.
|
||||
* @return {!Element} The log table element.
|
||||
* @private
|
||||
*/
|
||||
ensureUpdateContainer_(peerConnectionElement) {
|
||||
const tableId = peerConnectionElement.id + this.UPDATE_LOG_ID_SUFFIX_;
|
||||
|
||||
// Disable getElementById restriction here, since |tableId| is not always
|
||||
// a valid selector.
|
||||
// eslint-disable-next-line no-restricted-properties
|
||||
let tableElement = document.getElementById(tableId);
|
||||
if (!tableElement) {
|
||||
const tableContainer = document.createElement('div');
|
||||
tableContainer.className = this.UPDATE_LOG_CONTAINER_CLASS_;
|
||||
peerConnectionElement.appendChild(tableContainer);
|
||||
|
||||
tableElement = document.createElement('table');
|
||||
tableElement.className = this.UPDATE_LOG_TABLE_CLASS;
|
||||
tableElement.id = tableId;
|
||||
tableElement.border = 1;
|
||||
tableContainer.appendChild(tableElement);
|
||||
tableElement.appendChild(
|
||||
$('time-event-template').content.cloneNode(true));
|
||||
}
|
||||
return tableElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the last createOfferOnSuccess/createAnswerOnSuccess to compare to
|
||||
* setLocalDescription and visualize SDP munging.
|
||||
*
|
||||
* @param {!Element} tableElement The peerconnection update element.
|
||||
* @param {!PeerConnectionUpdateEntry} update The update to add.
|
||||
* @private
|
||||
*/
|
||||
setLastOfferAnswer_(tableElement, update) {
|
||||
tableElement['data-lastofferanswer'] = update.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the last createOfferOnSuccess/createAnswerOnSuccess to compare
|
||||
* to setLocalDescription and visualize SDP munging.
|
||||
*
|
||||
* @param {!Element} tableElement The peerconnection update element.
|
||||
* @private
|
||||
*/
|
||||
getLastOfferAnswer_(tableElement) {
|
||||
return tableElement['data-lastofferanswer'];
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue