[twilio-video] Add Network Quality stats for Participant (#38930)

* Add NetworkQualityStats for Participant

* chore: use consistent spacing in tests

* Set correct nullable properties for NetworkQuality stats
This commit is contained in:
Erick Delfin
2019-10-10 12:53:29 -07:00
committed by Armando Aguirre
parent aa35480024
commit 7a26429cbf
2 changed files with 65 additions and 31 deletions
+34
View File
@@ -4,6 +4,7 @@
// Darío Blanco <https://github.com/darioblanco>
// katashin <https://github.com/ktsn>
// Benjamin Santalucia <https://github.com/ben8p>
// Erick Delfin <https://github.com/nifled>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
@@ -170,6 +171,38 @@ export class MediaServerRemoteDescFailedError extends TwilioError {
code: 53403;
message: 'Server is unable to apply a remote media description';
}
export class NetworkQualityAudioStats extends NetworkQualityMediaStats { }
export class NetworkQualityBandwidthStats {
actual: number | null;
available: number | null;
level: NetworkQualityLevel | null;
}
export class NetworkQualityFractionLostStats {
fractionLost: number | null;
level: NetworkQualityLevel | null;
}
export class NetworkQualityLatencyStats {
jitter: number | null;
rtt: number | null;
level: NetworkQualityLevel | null;
}
export class NetworkQualityMediaStats {
send: NetworkQualityLevel;
recv: NetworkQualityLevel;
sendStats: NetworkQualitySendOrRecvStats | null;
recvStats: NetworkQualitySendOrRecvStats | null;
}
export class NetworkQualitySendOrRecvStats {
bandwidth: NetworkQualityBandwidthStats | null;
latency: NetworkQualityLatencyStats | null;
fractionLost: NetworkQualityFractionLostStats | null;
}
export class NetworkQualityStats {
level: NetworkQualityLevel;
audio: NetworkQualityAudioStats | null; // nullable depending on verbosity config
video: NetworkQualityVideoStats | null;
}
export class NetworkQualityVideoStats extends NetworkQualityMediaStats { }
export namespace Participant {
type Identity = string;
type SID = string;
@@ -179,6 +212,7 @@ export class Participant extends EventEmitter {
dataTracks: Map<Track.SID, DataTrackPublication>;
identity: Participant.Identity;
networkQualityLevel: NetworkQualityLevel | null;
networkQualityStats: NetworkQualityStats | null;
sid: Participant.SID;
state: string;
tracks: Map<Track.SID, TrackPublication>;
+31 -31
View File
@@ -18,15 +18,15 @@ async function initRoom() {
maxAudioBitrate: 500,
maxVideoBitrate: 200,
bandwidthProfile: {
video: {
dominantSpeakerPriority: 'high',
renderDimensions: {
low: {
height: 500,
width: null
}
}
video: {
dominantSpeakerPriority: 'high',
renderDimensions: {
low: {
height: 500,
width: null
}
}
}
}
});
await Video.connect('$TOKEN', {
@@ -62,42 +62,42 @@ function unpublishTracks() {
}
function participantConnected(participant: Video.Participant) {
participant.on('trackSubscribed', trackSubscribed);
participant.on('trackUnsubscribed', trackUnsubscribed);
participant.on('trackSubscribed', trackSubscribed);
participant.on('trackUnsubscribed', trackUnsubscribed);
participant.tracks.forEach(publication => {
const remotePublication = publication as Video.RemoteTrackPublication;
if (remotePublication.isSubscribed) {
trackSubscribed(remotePublication.track as Video.VideoTrack | Video.AudioTrack);
}
});
participant.tracks.forEach(publication => {
const remotePublication = publication as Video.RemoteTrackPublication;
if (remotePublication.isSubscribed) {
trackSubscribed(remotePublication.track as Video.VideoTrack | Video.AudioTrack);
}
});
}
function participantDisconnected(participant: Video.Participant) {
participant.tracks.forEach((publication) => {
const remotePublication = publication as Video.RemoteTrackPublication;
if (remotePublication.isSubscribed) {
const { track } = remotePublication;
if (track) trackUnsubscribed(track as Video.AudioTrack | Video.VideoTrack);
}
});
participant.tracks.forEach((publication) => {
const remotePublication = publication as Video.RemoteTrackPublication;
if (remotePublication.isSubscribed) {
const { track } = remotePublication;
if (track) trackUnsubscribed(track as Video.AudioTrack | Video.VideoTrack);
}
});
}
function trackSubscribed(track: Video.VideoTrack | Video.AudioTrack) {
const media = track.attach();
insertDomElement(media);
const media = track.attach();
insertDomElement(media);
}
function trackUnsubscribed(track: Video.VideoTrack | Video.AudioTrack) {
track.detach().forEach(element => element.remove());
// Alternative if Safari crashes when detaching tracks
track._attachments!.forEach((detachedElement) => detachedElement.remove());
track.detach().forEach(element => element.remove());
// Alternative if Safari crashes when detaching tracks
track._attachments!.forEach((detachedElement) => detachedElement.remove());
}
function insertDomElement(element: HTMLMediaElement) {
// Do something with the dom element
document.createElement('div');
element.appendChild(element);
// Do something with the dom element
document.createElement('div');
element.appendChild(element);
}
initRoom();