feat: Adds more debug information in the GSM bars popover (#7627)
This commit is contained in:
parent
aa488cb75c
commit
b5310573fc
|
@ -108,6 +108,7 @@ import {
|
|||
getBackendSafePath,
|
||||
getJitsiMeetGlobalNS
|
||||
} from './react/features/base/util';
|
||||
import { downloadJSON } from './react/features/base/util/downloadJSON';
|
||||
import { showDesktopPicker } from './react/features/desktop-picker';
|
||||
import { appendSuffix } from './react/features/display-name';
|
||||
import {
|
||||
|
@ -1221,19 +1222,8 @@ export default {
|
|||
// this can be called from console and will not have reference to this
|
||||
// that's why we reference the global var
|
||||
const logs = APP.connection.getLogs();
|
||||
const data = encodeURIComponent(JSON.stringify(logs, null, ' '));
|
||||
|
||||
const elem = document.createElement('a');
|
||||
|
||||
elem.download = filename;
|
||||
elem.href = `data:application/json;charset=utf-8,\n${data}`;
|
||||
elem.dataset.downloadurl
|
||||
= [ 'text/json', elem.download, elem.href ].join(':');
|
||||
elem.dispatchEvent(new MouseEvent('click', {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
downloadJSON(logs, filename);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -45,10 +45,8 @@
|
|||
@extend .connection-info__icon;
|
||||
}
|
||||
|
||||
.showmore {
|
||||
display: block;
|
||||
.connection-actions {
|
||||
margin: 10px auto;
|
||||
text-align: center;
|
||||
width: 90px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
},
|
||||
"connectionindicator": {
|
||||
"address": "Address:",
|
||||
"audio_ssrc": "Audio SSRC:",
|
||||
"bandwidth": "Estimated bandwidth:",
|
||||
"bitrate": "Bitrate:",
|
||||
"bridgeCount": "Server count: ",
|
||||
|
@ -126,9 +127,12 @@
|
|||
"remoteport": "Remote port:",
|
||||
"remoteport_plural": "Remote ports:",
|
||||
"resolution": "Resolution:",
|
||||
"savelogs": "Save logs",
|
||||
"participant_id": "Participant id:",
|
||||
"status": "Connection:",
|
||||
"transport": "Transport:",
|
||||
"transport_plural": "Transports:"
|
||||
"transport_plural": "Transports:",
|
||||
"video_ssrc": "Video SSRC:"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "Earlier",
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// @flow
|
||||
|
||||
/**
|
||||
* Downloads a JSON object.
|
||||
*
|
||||
* @param {Object} json - The JSON object to download.
|
||||
* @param {string} filename - The filename to give to the downloaded file.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function downloadJSON(json: Object, filename: string) {
|
||||
const data = encodeURIComponent(JSON.stringify(json, null, ' '));
|
||||
|
||||
const elem = document.createElement('a');
|
||||
|
||||
elem.download = filename;
|
||||
elem.href = `data:application/json;charset=utf-8,\n${data}`;
|
||||
elem.dataset.downloadurl = [ 'text/json', elem.download, elem.href ].join(':');
|
||||
elem.dispatchEvent(new MouseEvent('click', {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import getRoomName from '../base/config/getRoomName';
|
||||
import { downloadJSON } from '../base/util/downloadJSON';
|
||||
|
||||
|
||||
/**
|
||||
* Create an action for saving the conference logs.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function saveLogs() {
|
||||
return (dispatch, getState) => {
|
||||
|
||||
const logs = getState()['features/base/connection'].connection.getLogs();
|
||||
const roomName = getRoomName() || '';
|
||||
|
||||
downloadJSON(logs, `meetlog-${roomName}.json`);
|
||||
};
|
||||
}
|
|
@ -1,12 +1,17 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { Icon, IconConnectionActive, IconConnectionInactive } from '../../../base/icons';
|
||||
import { JitsiParticipantConnectionStatus } from '../../../base/lib-jitsi-meet';
|
||||
import { MEDIA_TYPE } from '../../../base/media';
|
||||
import { Popover } from '../../../base/popover';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { getTrackByMediaTypeAndParticipant } from '../../../base/tracks';
|
||||
import { ConnectionStatsTable } from '../../../connection-stats';
|
||||
import { saveLogs } from '../../actions';
|
||||
import AbstractConnectionIndicator, {
|
||||
INDICATOR_DISPLAY_THRESHOLD,
|
||||
type Props as AbstractProps,
|
||||
|
@ -62,12 +67,22 @@ type Props = AbstractProps & {
|
|||
*/
|
||||
alwaysVisible: boolean,
|
||||
|
||||
/**
|
||||
* The audio SSRC of this client.
|
||||
*/
|
||||
audioSsrc: number,
|
||||
|
||||
/**
|
||||
* The current condition of the user's connection, matching one of the
|
||||
* enumerated values in the library.
|
||||
*/
|
||||
connectionStatus: string,
|
||||
|
||||
/**
|
||||
* The Redux dispatch function.
|
||||
*/
|
||||
dispatch: Dispatch<any>,
|
||||
|
||||
/**
|
||||
* Whether or not clicking the indicator should display a popover for more
|
||||
* details.
|
||||
|
@ -93,7 +108,17 @@ type Props = AbstractProps & {
|
|||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function
|
||||
t: Function,
|
||||
|
||||
/**
|
||||
* The video SSRC of this client.
|
||||
*/
|
||||
videoSsrc: number,
|
||||
|
||||
/**
|
||||
* Invoked to save the conference logs.
|
||||
*/
|
||||
_onSaveLogs: Function
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -353,6 +378,7 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
|
|||
|
||||
return (
|
||||
<ConnectionStatsTable
|
||||
audioSsrc = { this.props.audioSsrc }
|
||||
bandwidth = { bandwidth }
|
||||
bitrate = { bitrate }
|
||||
bridgeCount = { bridgeCount }
|
||||
|
@ -362,15 +388,63 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
|
|||
framerate = { framerate }
|
||||
isLocalVideo = { this.props.isLocalVideo }
|
||||
maxEnabledResolution = { maxEnabledResolution }
|
||||
onSaveLogs = { this.props._onSaveLogs }
|
||||
onShowMore = { this._onToggleShowMore }
|
||||
packetLoss = { packetLoss }
|
||||
participantId = { this.props.participantId }
|
||||
region = { region }
|
||||
resolution = { resolution }
|
||||
serverRegion = { serverRegion }
|
||||
shouldShowMore = { this.state.showMoreStats }
|
||||
transport = { transport } />
|
||||
transport = { transport }
|
||||
videoSsrc = { this.props.videoSsrc } />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(ConnectionIndicator);
|
||||
|
||||
/**
|
||||
* Maps redux actions to the props of the component.
|
||||
*
|
||||
* @param {Function} dispatch - The redux action {@code dispatch} function.
|
||||
* @returns {{
|
||||
* _onSaveLogs: Function,
|
||||
* }}
|
||||
* @private
|
||||
*/
|
||||
export function _mapDispatchToProps(dispatch: Dispatch<any>) {
|
||||
return {
|
||||
/**
|
||||
* Saves the conference logs.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
_onSaveLogs() {
|
||||
dispatch(saveLogs());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Props} ownProps - The own props of the component.
|
||||
* @returns {Props}
|
||||
*/
|
||||
export function _mapStateToProps(state: Object, ownProps: Props) {
|
||||
|
||||
const firstVideoTrack = getTrackByMediaTypeAndParticipant(
|
||||
state['features/base/tracks'], MEDIA_TYPE.VIDEO, ownProps.participantId);
|
||||
const firstAudioTrack = getTrackByMediaTypeAndParticipant(
|
||||
state['features/base/tracks'], MEDIA_TYPE.AUDIO, ownProps.participantId);
|
||||
|
||||
return {
|
||||
audioSsrc: firstAudioTrack
|
||||
? state['features/base/conference'].conference.getSsrcByTrack(firstAudioTrack.jitsiTrack) : undefined,
|
||||
videoSsrc: firstVideoTrack
|
||||
? state['features/base/conference'].conference.getSsrcByTrack(firstVideoTrack.jitsiTrack) : undefined
|
||||
};
|
||||
}
|
||||
export default translate(connect(_mapStateToProps, _mapDispatchToProps)(ConnectionIndicator));
|
||||
|
|
|
@ -10,6 +10,11 @@ import { translate } from '../../base/i18n';
|
|||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The audio SSRC of this client.
|
||||
*/
|
||||
audioSsrc: number,
|
||||
|
||||
/**
|
||||
* Statistics related to bandwidth.
|
||||
* {{
|
||||
|
@ -49,6 +54,11 @@ type Props = {
|
|||
*/
|
||||
e2eRtt: number,
|
||||
|
||||
/**
|
||||
* The endpoint id of this client.
|
||||
*/
|
||||
participantId: string,
|
||||
|
||||
/**
|
||||
* Statistics related to frame rates for each ssrc.
|
||||
* {{
|
||||
|
@ -68,6 +78,11 @@ type Props = {
|
|||
*/
|
||||
maxEnabledResolution: number,
|
||||
|
||||
/**
|
||||
* Callback to invoke when the user clicks on the download logs link.
|
||||
*/
|
||||
onSaveLogs: Function,
|
||||
|
||||
/**
|
||||
* Callback to invoke when the show additional stats link is clicked.
|
||||
*/
|
||||
|
@ -114,6 +129,11 @@ type Props = {
|
|||
*/
|
||||
t: Function,
|
||||
|
||||
/**
|
||||
* The video SSRC of this client.
|
||||
*/
|
||||
videoSsrc: number,
|
||||
|
||||
/**
|
||||
* Statistics related to transports.
|
||||
*/
|
||||
|
@ -138,9 +158,11 @@ class ConnectionStatsTable extends Component<Props> {
|
|||
return (
|
||||
<div className = 'connection-info'>
|
||||
{ this._renderStatistics() }
|
||||
{ isLocalVideo ? this._renderShowMoreLink() : null }
|
||||
{ isLocalVideo && this.props.shouldShowMore
|
||||
? this._renderAdditionalStats() : null }
|
||||
<div className = 'connection-actions'>
|
||||
{ isLocalVideo ? this._renderSaveLogs() : null}
|
||||
{ this._renderShowMoreLink() }
|
||||
</div>
|
||||
{ this.props.shouldShowMore ? this._renderAdditionalStats() : null }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -153,12 +175,17 @@ class ConnectionStatsTable extends Component<Props> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderAdditionalStats() {
|
||||
const { isLocalVideo } = this.props;
|
||||
|
||||
return (
|
||||
<table className = 'connection-info__container'>
|
||||
<tbody>
|
||||
{ this._renderBandwidth() }
|
||||
{ this._renderTransport() }
|
||||
{ this._renderRegion() }
|
||||
{ isLocalVideo ? this._renderBandwidth() : null }
|
||||
{ isLocalVideo ? this._renderTransport() : null }
|
||||
{ isLocalVideo ? this._renderRegion() : null }
|
||||
{ this._renderAudioSsrc() }
|
||||
{ this._renderVideoSsrc() }
|
||||
{ this._renderParticipantId() }
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
|
@ -224,6 +251,66 @@ class ConnectionStatsTable extends Component<Props> {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a table row as a ReactElement for displaying the audio ssrc.
|
||||
* This will typically be something like "Audio SSRC: 12345".
|
||||
*
|
||||
* @returns {JSX.Element}
|
||||
* @private
|
||||
*/
|
||||
_renderAudioSsrc() {
|
||||
const { audioSsrc, t } = this.props;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<span>{ t('connectionindicator.audio_ssrc') }</span>
|
||||
</td>
|
||||
<td>{ audioSsrc || 'N/A' }</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a table row as a ReactElement for displaying the video ssrc.
|
||||
* This will typically be something like "Video SSRC: 12345".
|
||||
*
|
||||
* @returns {JSX.Element}
|
||||
* @private
|
||||
*/
|
||||
_renderVideoSsrc() {
|
||||
const { videoSsrc, t } = this.props;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<span>{ t('connectionindicator.video_ssrc') }</span>
|
||||
</td>
|
||||
<td>{ videoSsrc || 'N/A' }</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a table row as a ReactElement for displaying the endpoint id.
|
||||
* This will typically be something like "Endpoint id: 1e8fbg".
|
||||
*
|
||||
* @returns {JSX.Element}
|
||||
* @private
|
||||
*/
|
||||
_renderParticipantId() {
|
||||
const { participantId, t } = this.props;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<span>{ t('connectionindicator.participant_id') }</span>
|
||||
</td>
|
||||
<td>{ participantId || 'N/A' }</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a a table row as a ReactElement for displaying codec, if present.
|
||||
* This will typically be something like "Codecs (A/V): Opus, vp8".
|
||||
|
@ -455,6 +542,26 @@ class ConnectionStatsTable extends Component<Props> {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ReactElement for display a link to save the logs.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderSaveLogs() {
|
||||
return (
|
||||
<span>
|
||||
<a
|
||||
className = 'savelogs link'
|
||||
onClick = { this.props.onSaveLogs } >
|
||||
{ this.props.t('connectionindicator.savelogs') }
|
||||
</a>
|
||||
<span> | </span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a ReactElement for display a link to toggle showing additional
|
||||
* statistics.
|
||||
|
|
Loading…
Reference in New Issue