@observertc/samples-encoder
Version:
ObserveRTC Library for Encoding Samples
433 lines (390 loc) • 15.7 kB
text/typescript
import { MediaPlayoutStatsEncoder } from "./MediaPlayoutEncoder";
import { CertificateEncoder } from "./CertificateEncoder";
import { ClientSampleEncoder } from "./ClientSampleEncoder";
import { CodecStatsEncoder } from "./CodecStatsEncoder";
import { DataChannelEncoder } from "./DataChannelEncoder";
import { IceCandidateEncoder } from "./IceCandidateEncoder";
import { IceCandidatePairEncoder } from "./IceCandidatePairStatsEncoder";
import { IceTransportEncoder } from "./IceTransportEncoder";
import { InboundRtpEncoder } from "./InboundRtpEncoder";
import { InboundTrackSampleEncoder } from "./InboundTrackEncoder";
import { PeerConnectionSample as InputClientSample, PeerConnectionSample } from "./InputSamples";
import { MediaSourceStatsEncoder } from "./MediaSourceEncoder";
import { OutboundRtpEncoder } from "./OutboundRtpEncoder";
import { OutboundTrackSampleEncoder } from "./OutboundTrackEncoder";
import { ClientSample_PeerConnectionSample } from "./OutputSamples";
import { PeerConnectionTransportEncoder } from "./PeerConnectionTransportEncoder";
import { RemoteInboundRtpEncoder } from "./RemoteInboundRtpEncoder";
import { RemoteOutboundRtpEncoder } from "./RemoteOutboundRtpEncoder";
import {
AttachmentEncoder,
Encoder,
NumberToNumberEncoder,
OneTimePassStringToUint8ArrayEncoder,
OneTimePassUuidToByteArrayEncoder,
StringToStringEncoder,
stringToBytesArray,
uuidToByteArray
} from "./utils";
export class PeerConnectionSampleEncoder implements Encoder<PeerConnectionSample, ClientSample_PeerConnectionSample>{
private readonly _peerConnectionId: Uint8Array;
private _visited = false;
private _attachmentsEncoder: AttachmentEncoder;
private _scoreEncoder = new NumberToNumberEncoder();
private _scoreReasonsEncoder = new StringToStringEncoder();
private _inboundTracksEncoders = new Map<string, InboundTrackSampleEncoder>();
private _outboundTracksEncoders = new Map<string, OutboundTrackSampleEncoder>();
private _codecStatsEncoders = new Map<string, CodecStatsEncoder>();
private _inboundRtpEncoders = new Map<number, InboundRtpEncoder>();
private _remoteInboundRtpEncoders = new Map<number, RemoteInboundRtpEncoder>();
private _outboundRtpEncoders = new Map<number, OutboundRtpEncoder>();
private _remoteOutboundRtpEncoders = new Map<number, RemoteOutboundRtpEncoder>();
private _mediaSourceEncoders = new Map<string, MediaSourceStatsEncoder>();
private _mediaPlayoutEncoders = new Map<string, MediaPlayoutStatsEncoder>();
private _peerConnectionTransportEncoders = new Map<string, PeerConnectionTransportEncoder>();
private _dataChannelEncoders = new Map<string, DataChannelEncoder>();
private _iceTransportEncoders = new Map<string, IceTransportEncoder>();
private _iceCandidateEncoders = new Map<string, IceCandidateEncoder>();
private _iceCandidatePairEncoders = new Map<string, IceCandidatePairEncoder>();
private _certificateEncoders = new Map<string, CertificateEncoder>();
public constructor(
peerConnectionId: string,
public parent: ClientSampleEncoder,
) {
this._peerConnectionId = this.parent.settings.peerConnectionIdIsUuid
? uuidToByteArray(peerConnectionId)
: stringToBytesArray(peerConnectionId);
this._attachmentsEncoder = this.parent.attachmentEncoderFactory.createPeerConnectionSampleAttachmentEncoder();
}
public get visited(): boolean {
const result = this._visited;
this._visited = false;
return result;
}
public reset(): void {
this._attachmentsEncoder.reset();
this._scoreEncoder.reset();
this._scoreReasonsEncoder.reset();
this._inboundTracksEncoders.forEach((encoder) => encoder.reset());
this._outboundTracksEncoders.forEach((encoder) => encoder.reset());
this._codecStatsEncoders.forEach((encoder) => encoder.reset());
this._inboundRtpEncoders.forEach((encoder) => encoder.reset());
this._remoteInboundRtpEncoders.forEach((encoder) => encoder.reset());
this._outboundRtpEncoders.forEach((encoder) => encoder.reset());
this._remoteOutboundRtpEncoders.forEach((encoder) => encoder.reset());
this._mediaSourceEncoders.forEach((encoder) => encoder.reset());
this._mediaPlayoutEncoders.forEach((encoder) => encoder.reset());
this._peerConnectionTransportEncoders.forEach((encoder) => encoder.reset());
this._dataChannelEncoders.forEach((encoder) => encoder.reset());
this._iceTransportEncoders.forEach((encoder) => encoder.reset());
this._iceCandidateEncoders.forEach((encoder) => encoder.reset());
this._iceCandidatePairEncoders.forEach((encoder) => encoder.reset());
this._certificateEncoders.forEach((encoder) => encoder.reset());
}
public encode(sample: PeerConnectionSample): ClientSample_PeerConnectionSample {
this._visited = true;
const inboundTracks = sample.inboundTracks?.map(this._encodeInboundTracks.bind(this));
const outboundTracks = sample.outboundTracks?.map(this._encodeOutboundTracks.bind(this));
const codecs = sample.codecs?.map(this._encodeCodecStats.bind(this));
const inboundRtps = sample.inboundRtps?.map(this._encodeInboundRtp.bind(this));
const remoteInboundRtps = sample.remoteInboundRtps?.map(this._encodeRemoteInboundRtp.bind(this));
const outboundRtps = sample.outboundRtps?.map(this._encodeOutboundRtp.bind(this));
const remoteOutboundRtps = sample.remoteOutboundRtps?.map(this._encodeRemoteOutboundRtp.bind(this));
const mediaSources = sample.mediaSources?.map(this._encodeMediaSource.bind(this));
const mediaPlayouts = sample.mediaPlayouts?.map(this._encodeMediaPlayout.bind(this));
const peerConnectionTransports = sample.peerConnectionTransports?.map(this._encodePeerConnectionTransport.bind(this));
const dataChannels = sample.dataChannels?.map(this._encodeDataChannel.bind(this));
const iceTransports = sample.iceTransports?.map(this._encodeIceTransport.bind(this));
const iceCandidates = sample.iceCandidates?.map(this._encodeIceCandidate.bind(this));
const iceCandidatePairs = sample.iceCandidatePairs?.map(this._encodeIceCandidatePair.bind(this));
const certificates = sample.certificates?.map(this._encodeCertificate.bind(this));
return new ClientSample_PeerConnectionSample({
peerConnectionId: this._peerConnectionId,
attachments: this._attachmentsEncoder.encode(sample.attachments),
score: this._scoreEncoder.encode(sample.score),
scoreReasons: this._scoreReasonsEncoder.encode(sample.scoreReasons),
inboundTracks,
outboundTracks,
codecs,
inboundRtps,
remoteInboundRtps,
outboundRtps,
remoteOutboundRtps,
mediaSources,
mediaPlayouts,
peerConnectionTransports,
dataChannels,
iceTransports,
iceCandidates,
iceCandidatePairs,
certificates,
});
}
private _encodeCodecStats(input: Required<InputClientSample>['codecs'][number]) {
let encoder = this._codecStatsEncoders.get(input.id);
if (!encoder) {
encoder = new CodecStatsEncoder(
this.parent.attachmentEncoderFactory.createCodecStatsAttachmentEncoder()
);
this._codecStatsEncoders.set(input.id, encoder);
}
return encoder.encode(input);
}
private _encodeInboundTracks(input: Required<InputClientSample>['inboundTracks'][number]) {
let encoder = this._inboundTracksEncoders.get(input.id);
if (!encoder) {
encoder = new InboundTrackSampleEncoder(
this.parent.attachmentEncoderFactory.createInboundTrackAttachmentEncoder()
);
this._inboundTracksEncoders.set(input.id, encoder);
}
return encoder.encode(input);
}
private _encodeOutboundTracks(input: Required<InputClientSample>['outboundTracks'][number]) {
let encoder = this._outboundTracksEncoders.get(input.id);
if (!encoder) {
encoder = new OutboundTrackSampleEncoder(
this.parent.attachmentEncoderFactory.createOutboundTrackAttachmentEncoder()
);
this._outboundTracksEncoders.set(input.id, encoder);
}
return encoder.encode(input);
}
private _encodeInboundRtp(input: Required<InputClientSample>['inboundRtps'][number]) {
let encoder = this._inboundRtpEncoders.get(input.ssrc);
if (!encoder) {
const trackIdEncoder = this.parent.settings.trackIdIsUuid
? new OneTimePassUuidToByteArrayEncoder()
: new OneTimePassStringToUint8ArrayEncoder();
encoder = new InboundRtpEncoder(
input.ssrc,
trackIdEncoder,
this.parent.attachmentEncoderFactory.createInboundRtpAttachmentEncoder()
);
this._inboundRtpEncoders.set(input.ssrc, encoder);
}
return encoder.encode(input);
}
private _encodeOutboundRtp(input: Required<InputClientSample>['outboundRtps'][number]) {
let encoder = this._outboundRtpEncoders.get(input.ssrc);
if (!encoder) {
encoder = new OutboundRtpEncoder(
input.ssrc,
this.parent.attachmentEncoderFactory.createOutboundRtpAttachmentEncoder()
);
this._outboundRtpEncoders.set(input.ssrc, encoder);
}
return encoder.encode(input);
}
private _encodeRemoteInboundRtp(input: Required<InputClientSample>['remoteInboundRtps'][number]) {
let encoder = this._remoteInboundRtpEncoders.get(input.ssrc);
if (!encoder) {
encoder = new RemoteInboundRtpEncoder(
input.ssrc,
this.parent.attachmentEncoderFactory.createRemoteInboundRtpAttachmentEncoder()
);
this._remoteInboundRtpEncoders.set(input.ssrc, encoder);
}
return encoder.encode(input);
}
private _encodeRemoteOutboundRtp(input: Required<InputClientSample>['remoteOutboundRtps'][number]) {
let encoder = this._remoteOutboundRtpEncoders.get(input.ssrc);
if (!encoder) {
encoder = new RemoteOutboundRtpEncoder(
input.ssrc,
this.parent.attachmentEncoderFactory.createRemoteOutboundRtpAttachmentEncoder()
);
this._remoteOutboundRtpEncoders.set(input.ssrc, encoder);
}
return encoder.encode(input);
}
private _encodeDataChannel(input: Required<InputClientSample>['dataChannels'][number]) {
let encoder = this._dataChannelEncoders.get(input.id);
if (!encoder) {
encoder = new DataChannelEncoder(
this.parent.attachmentEncoderFactory.createDataChannelAttachmentEncoder()
);
this._dataChannelEncoders.set(input.id, encoder);
}
return encoder.encode(input);
}
private _encodeMediaSource(input: Required<InputClientSample>['mediaSources'][number]) {
let encoder = this._mediaSourceEncoders.get(input.id);
if (!encoder) {
encoder = new MediaSourceStatsEncoder(
this.parent.attachmentEncoderFactory.createMediaSourceAttachmentEncoder()
);
this._mediaSourceEncoders.set(input.id, encoder);
}
return encoder.encode(input);
}
private _encodeMediaPlayout(input: Required<InputClientSample>['mediaPlayouts'][number]) {
let encoder = this._mediaPlayoutEncoders.get(input.id);
if (!encoder) {
encoder = new MediaPlayoutStatsEncoder(
this.parent.attachmentEncoderFactory.createMediaPlayoutAttachmentEncoder()
);
this._mediaPlayoutEncoders.set(input.id, encoder);
}
return encoder.encode(input);
}
private _encodePeerConnectionTransport(input: Required<InputClientSample>['peerConnectionTransports'][number]) {
let encoder = this._peerConnectionTransportEncoders.get(input.id);
if (!encoder) {
encoder = new PeerConnectionTransportEncoder(
this.parent.attachmentEncoderFactory.createPeerConnectionTransportAttachmentEncoder()
);
this._peerConnectionTransportEncoders.set(input.id, encoder);
}
return encoder.encode(input);
}
private _encodeIceTransport(input: Required<InputClientSample>['iceTransports'][number]) {
let encoder = this._iceTransportEncoders.get(input.id);
if (!encoder) {
encoder = new IceTransportEncoder(
this.parent.attachmentEncoderFactory.createIceTransportAttachmentEncoder()
);
this._iceTransportEncoders.set(input.id, encoder);
}
return encoder.encode(input);
}
private _encodeIceCandidate(input: Required<InputClientSample>['iceCandidates'][number]) {
let encoder = this._iceCandidateEncoders.get(input.id);
if (!encoder) {
encoder = new IceCandidateEncoder(
this.parent.attachmentEncoderFactory.createIceCandidateAttachmentEncoder()
);
this._iceCandidateEncoders.set(input.id, encoder);
}
return encoder.encode(input);
}
private _encodeIceCandidatePair(input: Required<InputClientSample>['iceCandidatePairs'][number]) {
let encoder = this._iceCandidatePairEncoders.get(input.id);
if (!encoder) {
encoder = new IceCandidatePairEncoder(
this.parent.attachmentEncoderFactory.createIceCandidatePairAttachmentEncoder()
);
this._iceCandidatePairEncoders.set(input.id, encoder);
}
return encoder.encode(input);
}
private _encodeCertificate(input: Required<InputClientSample>['certificates'][number]) {
let encoder = this._certificateEncoders.get(input.id);
if (!encoder) {
encoder = new CertificateEncoder(
this.parent.attachmentEncoderFactory.createCertificateAttachmentEncoder()
);
this._certificateEncoders.set(input.id, encoder);
}
return encoder.encode(input);
}
public checkVisitsAndClean() {
let visited = false;
for (const [id, encoder] of [...this._inboundTracksEncoders.entries()]) {
if (!encoder.visited) {
this._inboundTracksEncoders.delete(id);
continue;
}
visited = true;
}
for (const [id, encoder] of [...this._outboundTracksEncoders.entries()]) {
if (!encoder.visited) {
this._outboundTracksEncoders.delete(id);
continue;
}
visited = true;
}
for (const [id, encoder] of [...this._codecStatsEncoders.entries()]) {
if (!encoder.visited) {
this._codecStatsEncoders.delete(id);
continue;
}
visited = true;
}
for (const [ssrc, encoder] of [...this._inboundRtpEncoders.entries()]) {
if (!encoder.visited) {
this._inboundRtpEncoders.delete(ssrc);
continue;
}
visited = true;
}
for (const [ssrc, encoder] of [...this._remoteInboundRtpEncoders.entries()]) {
if (!encoder.visited) {
this._remoteInboundRtpEncoders.delete(ssrc);
continue;
}
visited = true;
}
for (const [ssrc, encoder] of [...this._outboundRtpEncoders.entries()]) {
if (!encoder.visited) {
this._outboundRtpEncoders.delete(ssrc);
continue;
}
visited = true;
}
for (const [ssrc, encoder] of [...this._remoteOutboundRtpEncoders.entries()]) {
if (!encoder.visited) {
this._remoteOutboundRtpEncoders.delete(ssrc);
continue;
}
visited = true;
}
for (const [id, encoder] of [...this._mediaSourceEncoders.entries()]) {
if (!encoder.visited) {
this._mediaSourceEncoders.delete(id);
continue;
}
visited = true;
}
for (const [id, encoder] of [...this._mediaPlayoutEncoders.entries()]) {
if (!encoder.visited) {
this._mediaPlayoutEncoders.delete(id);
continue;
}
visited = true;
}
for (const [id, encoder] of [...this._peerConnectionTransportEncoders.entries()]) {
if (!encoder.visited) {
this._peerConnectionTransportEncoders.delete(id);
continue;
}
visited = true;
}
for (const [id, encoder] of [...this._dataChannelEncoders.entries()]) {
if (!encoder.visited) {
this._dataChannelEncoders.delete(id);
continue;
}
visited = true;
}
for (const [id, encoder] of [...this._iceTransportEncoders.entries()]) {
if (!encoder.visited) {
this._iceTransportEncoders.delete(id);
continue;
}
visited = true;
}
for (const [id, encoder] of [...this._iceCandidateEncoders.entries()]) {
if (!encoder.visited) {
this._iceCandidateEncoders.delete(id);
continue;
}
visited = true;
}
for (const [id, encoder] of [...this._iceCandidatePairEncoders.entries()]) {
if (!encoder.visited) {
this._iceCandidatePairEncoders.delete(id);
continue;
}
visited = true;
}
for (const [id, encoder] of [...this._certificateEncoders.entries()]) {
if (!encoder.visited) {
this._certificateEncoders.delete(id);
continue;
}
visited = true;
}
return visited;
}
}