@observertc/observer-js 0.9.27-beta → 0.30.0-e12fcb4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ObservedCall.d.ts +54 -0
- package/lib/ObservedCall.d.ts.map +1 -0
- package/lib/ObservedCall.js +166 -0
- package/lib/ObservedClient.d.ts +73 -0
- package/lib/ObservedClient.d.ts.map +1 -0
- package/lib/ObservedClient.js +487 -0
- package/lib/ObservedInboundTrack.d.ts +65 -0
- package/lib/ObservedInboundTrack.d.ts.map +1 -0
- package/lib/ObservedInboundTrack.js +192 -0
- package/lib/ObservedOutboundTrack.d.ts +55 -0
- package/lib/ObservedOutboundTrack.d.ts.map +1 -0
- package/lib/ObservedOutboundTrack.js +166 -0
- package/lib/ObservedPeerConnection.d.ts +57 -0
- package/lib/ObservedPeerConnection.d.ts.map +1 -0
- package/lib/ObservedPeerConnection.js +217 -0
- package/lib/Observer.d.ts +26 -1465
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +53 -605
- package/lib/{sinks/ObserverSink.d.ts → ReportsCollector.d.ts} +7 -23
- package/lib/ReportsCollector.d.ts.map +1 -0
- package/lib/{sinks/ObserverSink.js → ReportsCollector.js} +27 -85
- package/lib/common/ReportsCollector.d.ts +21 -24
- package/lib/common/ReportsCollector.d.ts.map +1 -1
- package/lib/common/ReportsCollector.js +24 -0
- package/lib/common/SingleExecutor.d.ts +3 -0
- package/lib/common/SingleExecutor.d.ts.map +1 -0
- package/lib/common/SingleExecutor.js +31 -0
- package/lib/common/TypedEventEmitter.d.ts +22 -0
- package/lib/common/TypedEventEmitter.d.ts.map +1 -0
- package/lib/common/TypedEventEmitter.js +11 -0
- package/lib/common/callEventReports.d.ts.map +1 -0
- package/lib/common/logger.d.ts +3 -9
- package/lib/common/logger.d.ts.map +1 -1
- package/lib/common/logger.js +58 -141
- package/lib/common/types.d.ts +2 -14
- package/lib/common/types.d.ts.map +1 -1
- package/lib/common/utils.d.ts +1 -0
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +6 -1
- package/lib/index.d.ts +8 -19
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +7 -2
- package/package.json +1 -1
- package/src/ObservedCall.ts +201 -0
- package/src/ObservedClient.ts +681 -0
- package/src/ObservedInboundTrack.ts +238 -0
- package/src/ObservedOutboundTrack.ts +205 -0
- package/src/ObservedPeerConnection.ts +249 -0
- package/src/Observer.ts +86 -442
- package/src/{sinks/ObserverSink.ts → ReportsCollector.ts} +29 -94
- package/src/common/ReportsCollector.ts +48 -23
- package/src/common/SingleExecutor.ts +36 -0
- package/src/common/TypedEventEmitter.ts +32 -0
- package/src/common/logger.ts +58 -161
- package/src/common/types.ts +4 -24
- package/src/common/utils.ts +6 -0
- package/src/index.ts +12 -23
- package/lib/Evaluator.d.ts +0 -43
- package/lib/Evaluator.d.ts.map +0 -1
- package/lib/Evaluator.js +0 -171
- package/lib/common/Semaphore.d.ts +0 -31
- package/lib/common/Semaphore.d.ts.map +0 -1
- package/lib/common/Semaphore.js +0 -16
- package/lib/entries/CallEntry.d.ts +0 -619
- package/lib/entries/CallEntry.d.ts.map +0 -1
- package/lib/entries/CallEntry.js +0 -75
- package/lib/entries/ClientEntry.d.ts +0 -478
- package/lib/entries/ClientEntry.d.ts.map +0 -1
- package/lib/entries/ClientEntry.js +0 -114
- package/lib/entries/InboundTrackEntry.d.ts +0 -682
- package/lib/entries/InboundTrackEntry.d.ts.map +0 -1
- package/lib/entries/InboundTrackEntry.js +0 -76
- package/lib/entries/OutboundTrackEntry.d.ts +0 -682
- package/lib/entries/OutboundTrackEntry.d.ts.map +0 -1
- package/lib/entries/OutboundTrackEntry.js +0 -73
- package/lib/entries/PeerConnectionEntry.d.ts +0 -505
- package/lib/entries/PeerConnectionEntry.d.ts.map +0 -1
- package/lib/entries/PeerConnectionEntry.js +0 -144
- package/lib/entries/SfuEntry.d.ts +0 -150
- package/lib/entries/SfuEntry.d.ts.map +0 -1
- package/lib/entries/SfuEntry.js +0 -77
- package/lib/entries/SfuInboundRtpPadEntry.d.ts +0 -14
- package/lib/entries/SfuInboundRtpPadEntry.d.ts.map +0 -1
- package/lib/entries/SfuInboundRtpPadEntry.js +0 -49
- package/lib/entries/SfuOutboundRtpPadEntry.d.ts +0 -14
- package/lib/entries/SfuOutboundRtpPadEntry.d.ts.map +0 -1
- package/lib/entries/SfuOutboundRtpPadEntry.js +0 -47
- package/lib/entries/SfuSctpChannelEntry.d.ts +0 -12
- package/lib/entries/SfuSctpChannelEntry.d.ts.map +0 -1
- package/lib/entries/SfuSctpChannelEntry.js +0 -43
- package/lib/entries/SfuTransportEntry.d.ts +0 -82
- package/lib/entries/SfuTransportEntry.d.ts.map +0 -1
- package/lib/entries/SfuTransportEntry.js +0 -122
- package/lib/evaluators/SetClientsCoordinateEvaluator.d.ts +0 -9
- package/lib/evaluators/SetClientsCoordinateEvaluator.d.ts.map +0 -1
- package/lib/evaluators/SetClientsCoordinateEvaluator.js +0 -95
- package/lib/middlewares/CallOperationsContext.d.ts +0 -18
- package/lib/middlewares/CallOperationsContext.d.ts.map +0 -1
- package/lib/middlewares/CallOperationsContext.js +0 -27
- package/lib/middlewares/CallProcessor.d.ts +0 -6
- package/lib/middlewares/CallProcessor.d.ts.map +0 -1
- package/lib/middlewares/CallProcessor.js +0 -36
- package/lib/middlewares/CommitTransactionMiddleware.d.ts +0 -6
- package/lib/middlewares/CommitTransactionMiddleware.d.ts.map +0 -1
- package/lib/middlewares/CommitTransactionMiddleware.js +0 -179
- package/lib/middlewares/DeleteOutdatedCallEntries.d.ts +0 -6
- package/lib/middlewares/DeleteOutdatedCallEntries.d.ts.map +0 -1
- package/lib/middlewares/DeleteOutdatedCallEntries.js +0 -121
- package/lib/middlewares/DeleteOutdatedSfuEntries.d.ts +0 -6
- package/lib/middlewares/DeleteOutdatedSfuEntries.d.ts.map +0 -1
- package/lib/middlewares/DeleteOutdatedSfuEntries.js +0 -127
- package/lib/middlewares/Middleware.d.ts +0 -3
- package/lib/middlewares/Middleware.d.ts.map +0 -1
- package/lib/middlewares/Middleware.js +0 -21
- package/lib/middlewares/Processor.d.ts +0 -9
- package/lib/middlewares/Processor.d.ts.map +0 -1
- package/lib/middlewares/Processor.js +0 -54
- package/lib/middlewares/TransactionContext.d.ts +0 -35
- package/lib/middlewares/TransactionContext.d.ts.map +0 -1
- package/lib/middlewares/TransactionContext.js +0 -90
- package/lib/middlewares/TransactoinProcessor.d.ts +0 -6
- package/lib/middlewares/TransactoinProcessor.d.ts.map +0 -1
- package/lib/middlewares/TransactoinProcessor.js +0 -17
- package/lib/middlewares/VisitObservedCallsMiddleware.d.ts +0 -7
- package/lib/middlewares/VisitObservedCallsMiddleware.d.ts.map +0 -1
- package/lib/middlewares/VisitObservedCallsMiddleware.js +0 -96
- package/lib/middlewares/VisitObservedSfusMiddleware.d.ts +0 -6
- package/lib/middlewares/VisitObservedSfusMiddleware.d.ts.map +0 -1
- package/lib/middlewares/VisitObservedSfusMiddleware.js +0 -151
- package/lib/middlewares/visitors/visitClient.d.ts +0 -5
- package/lib/middlewares/visitors/visitClient.d.ts.map +0 -1
- package/lib/middlewares/visitors/visitClient.js +0 -174
- package/lib/middlewares/visitors/visitInboundAudioTrack.d.ts +0 -5
- package/lib/middlewares/visitors/visitInboundAudioTrack.d.ts.map +0 -1
- package/lib/middlewares/visitors/visitInboundAudioTrack.js +0 -93
- package/lib/middlewares/visitors/visitInboundVideoTrack.d.ts +0 -5
- package/lib/middlewares/visitors/visitInboundVideoTrack.d.ts.map +0 -1
- package/lib/middlewares/visitors/visitInboundVideoTrack.js +0 -94
- package/lib/middlewares/visitors/visitOutboundAudioTrack.d.ts +0 -5
- package/lib/middlewares/visitors/visitOutboundAudioTrack.d.ts.map +0 -1
- package/lib/middlewares/visitors/visitOutboundAudioTrack.js +0 -90
- package/lib/middlewares/visitors/visitOutboundVideoTarck.d.ts +0 -5
- package/lib/middlewares/visitors/visitOutboundVideoTarck.d.ts.map +0 -1
- package/lib/middlewares/visitors/visitOutboundVideoTarck.js +0 -90
- package/lib/middlewares/visitors/visitPeerConnection.d.ts +0 -5
- package/lib/middlewares/visitors/visitPeerConnection.d.ts.map +0 -1
- package/lib/middlewares/visitors/visitPeerConnection.js +0 -111
- package/lib/middlewares/visitors/visitSfu.d.ts +0 -5
- package/lib/middlewares/visitors/visitSfu.d.ts.map +0 -1
- package/lib/middlewares/visitors/visitSfu.js +0 -78
- package/lib/middlewares/visitors/visitSfuInboundRtpPad.d.ts +0 -5
- package/lib/middlewares/visitors/visitSfuInboundRtpPad.d.ts.map +0 -1
- package/lib/middlewares/visitors/visitSfuInboundRtpPad.js +0 -56
- package/lib/middlewares/visitors/visitSfuOutboundRtpPad.d.ts +0 -5
- package/lib/middlewares/visitors/visitSfuOutboundRtpPad.d.ts.map +0 -1
- package/lib/middlewares/visitors/visitSfuOutboundRtpPad.js +0 -56
- package/lib/middlewares/visitors/visitSfuSctpChannel.d.ts +0 -5
- package/lib/middlewares/visitors/visitSfuSctpChannel.d.ts.map +0 -1
- package/lib/middlewares/visitors/visitSfuSctpChannel.js +0 -55
- package/lib/middlewares/visitors/visitSfuTransport.d.ts +0 -5
- package/lib/middlewares/visitors/visitSfuTransport.d.ts.map +0 -1
- package/lib/middlewares/visitors/visitSfuTransport.js +0 -56
- package/lib/processes/closePeerConnectionProcess.d.ts +0 -10
- package/lib/processes/closePeerConnectionProcess.d.ts.map +0 -1
- package/lib/processes/closePeerConnectionProcess.js +0 -51
- package/lib/processes/detachClientProcess.d.ts +0 -14
- package/lib/processes/detachClientProcess.d.ts.map +0 -1
- package/lib/processes/detachClientProcess.js +0 -106
- package/lib/processes/findRemoteMatches.d.ts +0 -9
- package/lib/processes/findRemoteMatches.d.ts.map +0 -1
- package/lib/processes/findRemoteMatches.js +0 -96
- package/lib/processes/inboundTrackRemoved.d.ts +0 -9
- package/lib/processes/inboundTrackRemoved.d.ts.map +0 -1
- package/lib/processes/inboundTrackRemoved.js +0 -22
- package/lib/processes/joinClientProcess.d.ts +0 -11
- package/lib/processes/joinClientProcess.d.ts.map +0 -1
- package/lib/processes/joinClientProcess.js +0 -120
- package/lib/processes/outboundTrackRemoved.d.ts +0 -9
- package/lib/processes/outboundTrackRemoved.d.ts.map +0 -1
- package/lib/processes/outboundTrackRemoved.js +0 -22
- package/lib/samples/ObservedCall.d.ts +0 -17
- package/lib/samples/ObservedCall.d.ts.map +0 -1
- package/lib/samples/ObservedCall.js +0 -29
- package/lib/samples/ObservedCalls.d.ts +0 -19
- package/lib/samples/ObservedCalls.d.ts.map +0 -1
- package/lib/samples/ObservedCalls.js +0 -113
- package/lib/samples/ObservedClient.d.ts +0 -28
- package/lib/samples/ObservedClient.d.ts.map +0 -1
- package/lib/samples/ObservedClient.js +0 -110
- package/lib/samples/ObservedInboundAudioTrack.d.ts +0 -17
- package/lib/samples/ObservedInboundAudioTrack.d.ts.map +0 -1
- package/lib/samples/ObservedInboundAudioTrack.js +0 -17
- package/lib/samples/ObservedInboundVideoTrack.d.ts +0 -17
- package/lib/samples/ObservedInboundVideoTrack.d.ts.map +0 -1
- package/lib/samples/ObservedInboundVideoTrack.js +0 -17
- package/lib/samples/ObservedOutboundAudioTrack.d.ts +0 -16
- package/lib/samples/ObservedOutboundAudioTrack.d.ts.map +0 -1
- package/lib/samples/ObservedOutboundAudioTrack.js +0 -17
- package/lib/samples/ObservedOutboundVideoTrack.d.ts +0 -16
- package/lib/samples/ObservedOutboundVideoTrack.d.ts.map +0 -1
- package/lib/samples/ObservedOutboundVideoTrack.js +0 -17
- package/lib/samples/ObservedPeerConnection.d.ts +0 -47
- package/lib/samples/ObservedPeerConnection.d.ts.map +0 -1
- package/lib/samples/ObservedPeerConnection.js +0 -130
- package/lib/samples/ObservedSfu.d.ts +0 -27
- package/lib/samples/ObservedSfu.d.ts.map +0 -1
- package/lib/samples/ObservedSfu.js +0 -65
- package/lib/samples/ObservedSfuInboundRtpPad.d.ts +0 -15
- package/lib/samples/ObservedSfuInboundRtpPad.d.ts.map +0 -1
- package/lib/samples/ObservedSfuInboundRtpPad.js +0 -17
- package/lib/samples/ObservedSfuOutboundRtpPad.d.ts +0 -15
- package/lib/samples/ObservedSfuOutboundRtpPad.d.ts.map +0 -1
- package/lib/samples/ObservedSfuOutboundRtpPad.js +0 -17
- package/lib/samples/ObservedSfuSctpChannel.d.ts +0 -15
- package/lib/samples/ObservedSfuSctpChannel.d.ts.map +0 -1
- package/lib/samples/ObservedSfuSctpChannel.js +0 -17
- package/lib/samples/ObservedSfuTransport.d.ts +0 -30
- package/lib/samples/ObservedSfuTransport.d.ts.map +0 -1
- package/lib/samples/ObservedSfuTransport.js +0 -86
- package/lib/samples/ObservedSfus.d.ts +0 -16
- package/lib/samples/ObservedSfus.d.ts.map +0 -1
- package/lib/samples/ObservedSfus.js +0 -72
- package/lib/sinks/ObserverSink.d.ts.map +0 -1
- package/lib/sinks/callEventReports.d.ts.map +0 -1
- package/lib/sources/ObservedCallSource.d.ts +0 -18
- package/lib/sources/ObservedCallSource.d.ts.map +0 -1
- package/lib/sources/ObservedCallSource.js +0 -2
- package/lib/sources/ObservedClientSource.d.ts +0 -19
- package/lib/sources/ObservedClientSource.d.ts.map +0 -1
- package/lib/sources/ObservedClientSource.js +0 -2
- package/lib/sources/ObservedSfuSource.d.ts +0 -15
- package/lib/sources/ObservedSfuSource.d.ts.map +0 -1
- package/lib/sources/ObservedSfuSource.js +0 -2
- package/lib/sources/Sources.d.ts +0 -49
- package/lib/sources/Sources.d.ts.map +0 -1
- package/lib/sources/Sources.js +0 -213
- package/src/Evaluator.ts +0 -229
- package/src/common/Semaphore.ts +0 -45
- package/src/entries/CallEntry.ts +0 -62
- package/src/entries/ClientEntry.ts +0 -106
- package/src/entries/InboundTrackEntry.ts +0 -74
- package/src/entries/OutboundTrackEntry.ts +0 -72
- package/src/entries/PeerConnectionEntry.ts +0 -133
- package/src/entries/SfuEntry.ts +0 -62
- package/src/entries/SfuInboundRtpPadEntry.ts +0 -46
- package/src/entries/SfuOutboundRtpPadEntry.ts +0 -44
- package/src/entries/SfuSctpChannelEntry.ts +0 -39
- package/src/entries/SfuTransportEntry.ts +0 -109
- package/src/evaluators/SetClientsCoordinateEvaluator.ts +0 -78
- package/src/middlewares/CallOperationsContext.ts +0 -56
- package/src/middlewares/CallProcessor.ts +0 -38
- package/src/middlewares/CommitTransactionMiddleware.ts +0 -328
- package/src/middlewares/DeleteOutdatedCallEntries.ts +0 -159
- package/src/middlewares/DeleteOutdatedSfuEntries.ts +0 -168
- package/src/middlewares/Middleware.ts +0 -10
- package/src/middlewares/Processor.ts +0 -59
- package/src/middlewares/TransactionContext.ts +0 -176
- package/src/middlewares/TransactoinProcessor.ts +0 -28
- package/src/middlewares/VisitObservedCallsMiddleware.ts +0 -172
- package/src/middlewares/VisitObservedSfusMiddleware.ts +0 -203
- package/src/middlewares/visitors/visitClient.ts +0 -239
- package/src/middlewares/visitors/visitInboundAudioTrack.ts +0 -113
- package/src/middlewares/visitors/visitInboundVideoTrack.ts +0 -117
- package/src/middlewares/visitors/visitOutboundAudioTrack.ts +0 -100
- package/src/middlewares/visitors/visitOutboundVideoTarck.ts +0 -102
- package/src/middlewares/visitors/visitPeerConnection.ts +0 -151
- package/src/middlewares/visitors/visitSfu.ts +0 -70
- package/src/middlewares/visitors/visitSfuInboundRtpPad.ts +0 -52
- package/src/middlewares/visitors/visitSfuOutboundRtpPad.ts +0 -53
- package/src/middlewares/visitors/visitSfuSctpChannel.ts +0 -50
- package/src/middlewares/visitors/visitSfuTransport.ts +0 -50
- package/src/processes/closePeerConnectionProcess.ts +0 -54
- package/src/processes/detachClientProcess.ts +0 -136
- package/src/processes/findRemoteMatches.ts +0 -104
- package/src/processes/inboundTrackRemoved.ts +0 -22
- package/src/processes/joinClientProcess.ts +0 -138
- package/src/processes/outboundTrackRemoved.ts +0 -22
- package/src/samples/ObservedCall.ts +0 -49
- package/src/samples/ObservedCalls.ts +0 -143
- package/src/samples/ObservedClient.ts +0 -172
- package/src/samples/ObservedInboundAudioTrack.ts +0 -35
- package/src/samples/ObservedInboundVideoTrack.ts +0 -36
- package/src/samples/ObservedOutboundAudioTrack.ts +0 -35
- package/src/samples/ObservedOutboundVideoTrack.ts +0 -35
- package/src/samples/ObservedPeerConnection.ts +0 -227
- package/src/samples/ObservedSfu.ts +0 -115
- package/src/samples/ObservedSfuInboundRtpPad.ts +0 -35
- package/src/samples/ObservedSfuOutboundRtpPad.ts +0 -35
- package/src/samples/ObservedSfuSctpChannel.ts +0 -35
- package/src/samples/ObservedSfuTransport.ts +0 -142
- package/src/samples/ObservedSfus.ts +0 -95
- package/src/sources/ObservedCallSource.ts +0 -26
- package/src/sources/ObservedClientSource.ts +0 -28
- package/src/sources/ObservedSfuSource.ts +0 -19
- package/src/sources/Sources.ts +0 -301
- /package/lib/{sinks → common}/callEventReports.d.ts +0 -0
- /package/lib/{sinks → common}/callEventReports.js +0 -0
- /package/src/{sinks → common}/callEventReports.ts +0 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { StorageProvider } from './storages/StorageProvider';
|
|
3
|
+
import * as Models from './models/Models';
|
|
4
|
+
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
5
|
+
import { InboundAudioTrack, InboundVideoTrack } from '@observertc/sample-schemas-js';
|
|
6
|
+
import { ObservedOutboundTrack } from './ObservedOutboundTrack';
|
|
7
|
+
import { InboundAudioTrackReport, InboundVideoTrackReport } from '@observertc/report-schemas-js';
|
|
8
|
+
import { MediaKind } from './common/types';
|
|
9
|
+
import { createSingleExecutor } from './common/SingleExecutor';
|
|
10
|
+
|
|
11
|
+
export type ObservedInboundTrackConfig<K extends MediaKind> = {
|
|
12
|
+
trackId: string;
|
|
13
|
+
kind: K;
|
|
14
|
+
sfuStreamId?: string;
|
|
15
|
+
sfuSinkId?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type ObservedInboundTrackEvents<K extends MediaKind> = {
|
|
19
|
+
update: [],
|
|
20
|
+
close: [],
|
|
21
|
+
remoteoutboundtrack: [ObservedOutboundTrack<K>],
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type ObservedInboundTrackStatsUpdate<K extends MediaKind> = K extends 'audio' ? InboundAudioTrack : InboundVideoTrack;
|
|
25
|
+
|
|
26
|
+
export type ObservedInboundTrackStats<K extends MediaKind> = ObservedInboundTrackStatsUpdate<K> & {
|
|
27
|
+
ssrc: number;
|
|
28
|
+
bitrate: number;
|
|
29
|
+
fractionLost: number;
|
|
30
|
+
rttInMs?: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// {
|
|
34
|
+
// [Property in keyof ObservedInboundTrackStats<K>]: ObservedInboundTrackStats<K>[Property];
|
|
35
|
+
// }
|
|
36
|
+
|
|
37
|
+
export declare interface ObservedInboundTrack<Kind extends MediaKind> {
|
|
38
|
+
on<U extends keyof ObservedInboundTrackEvents<Kind>>(event: U, listener: (...args: ObservedInboundTrackEvents<Kind>[U]) => void): this;
|
|
39
|
+
off<U extends keyof ObservedInboundTrackEvents<Kind>>(event: U, listener: (...args: ObservedInboundTrackEvents<Kind>[U]) => void): this;
|
|
40
|
+
once<U extends keyof ObservedInboundTrackEvents<Kind>>(event: U, listener: (...args: ObservedInboundTrackEvents<Kind>[U]) => void): this;
|
|
41
|
+
emit<U extends keyof ObservedInboundTrackEvents<Kind>>(event: U, ...args: ObservedInboundTrackEvents<Kind>[U]): boolean;
|
|
42
|
+
update(sample: ObservedInboundTrackStatsUpdate<Kind>, timestamp: number): void;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
46
|
+
public static async create<K extends MediaKind>(
|
|
47
|
+
config: ObservedInboundTrackConfig<K>,
|
|
48
|
+
peerConnection: ObservedPeerConnection,
|
|
49
|
+
storageProvider: StorageProvider,
|
|
50
|
+
) {
|
|
51
|
+
const model = new Models.InboundTrack({
|
|
52
|
+
serviceId: peerConnection.client.serviceId,
|
|
53
|
+
roomId: peerConnection.client.roomId,
|
|
54
|
+
callId: peerConnection.client.callId,
|
|
55
|
+
clientId: peerConnection.client.clientId,
|
|
56
|
+
mediaUnitId: peerConnection.client.mediaUnitId,
|
|
57
|
+
peerConnectionId: peerConnection.peerConnectionId,
|
|
58
|
+
trackId: config.trackId,
|
|
59
|
+
kind: config.kind,
|
|
60
|
+
sfuStreamId: config.sfuStreamId,
|
|
61
|
+
sfuSinkId: config.sfuSinkId,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const alreadyInserted = await storageProvider.inboundTrackStorage.insert(config.trackId, model);
|
|
65
|
+
|
|
66
|
+
if (alreadyInserted) throw new Error(`InboundAudioTrack with id ${config.trackId} already exists`);
|
|
67
|
+
|
|
68
|
+
return new ObservedInboundTrack<K>(model, peerConnection, storageProvider);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private readonly _stats = new Map<number, ObservedInboundTrackStats<Kind>>();
|
|
72
|
+
private readonly _execute = createSingleExecutor();
|
|
73
|
+
|
|
74
|
+
private _closed = false;
|
|
75
|
+
private _updated = Date.now();
|
|
76
|
+
private _remoteOutboundTrack?: ObservedOutboundTrack<Kind>;
|
|
77
|
+
public bitrate = -1;
|
|
78
|
+
public rttInMs = -1;
|
|
79
|
+
|
|
80
|
+
private constructor(
|
|
81
|
+
private readonly _model: Models.InboundTrack,
|
|
82
|
+
public readonly peerConnection: ObservedPeerConnection,
|
|
83
|
+
private readonly _storageProvider: StorageProvider,
|
|
84
|
+
) {
|
|
85
|
+
super();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public get serviceId() {
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
90
|
+
return this._model.serviceId!;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public get roomId() {
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
95
|
+
return this._model.roomId!;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public get callId() {
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
100
|
+
return this._model.callId!;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public get clientId() {
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
105
|
+
return this._model.clientId!;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public get mediaUnitId() {
|
|
109
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
110
|
+
return this._model.mediaUnitId!;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public get peerConnectionId() {
|
|
114
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
115
|
+
return this._model.peerConnectionId!;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public get trackId() {
|
|
119
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
120
|
+
return this._model.trackId!;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public get kind(): Kind {
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
125
|
+
return this._model.kind! as Kind;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public get sfuStreamId() {
|
|
129
|
+
return this._model.sfuStreamId;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public get sfuSinkId() {
|
|
133
|
+
return this._model.sfuSinkId;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public get updated() {
|
|
137
|
+
return this._updated;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public get stats(): ReadonlyMap<number, ObservedInboundTrackStats<Kind>> {
|
|
141
|
+
return this._stats;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public get reports() {
|
|
145
|
+
return this.peerConnection.reports;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public set remoteOutboundTrack(track: ObservedOutboundTrack<Kind> | undefined) {
|
|
149
|
+
if (this._closed) return;
|
|
150
|
+
if (this._remoteOutboundTrack) return;
|
|
151
|
+
if (!track) return;
|
|
152
|
+
track?.once('close', () => {
|
|
153
|
+
this._remoteOutboundTrack = undefined;
|
|
154
|
+
});
|
|
155
|
+
this._remoteOutboundTrack = track;
|
|
156
|
+
this.emit('remoteoutboundtrack', track);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public get remoteOutboundTrack() {
|
|
160
|
+
return this._remoteOutboundTrack;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public get closed() {
|
|
164
|
+
return this._closed;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public close() {
|
|
168
|
+
if (this._closed) return;
|
|
169
|
+
|
|
170
|
+
this._closed = true;
|
|
171
|
+
|
|
172
|
+
this._execute(() => this._storageProvider.inboundTrackStorage.remove(this.trackId))
|
|
173
|
+
.catch(() => void 0)
|
|
174
|
+
.finally(() => this.emit('close'));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public async update(sample: ObservedInboundTrackStatsUpdate<Kind>, timestamp: number) {
|
|
178
|
+
if (this._closed) return;
|
|
179
|
+
let executeSave = false;
|
|
180
|
+
|
|
181
|
+
const report: InboundAudioTrackReport | InboundVideoTrackReport = {
|
|
182
|
+
serviceId: this.peerConnection.client.call.serviceId,
|
|
183
|
+
roomId: this.peerConnection.client.call.roomId,
|
|
184
|
+
callId: this.peerConnection.client.call.callId,
|
|
185
|
+
clientId: this.peerConnection.client.clientId,
|
|
186
|
+
userId: this.peerConnection.client.userId,
|
|
187
|
+
mediaUnitId: this.peerConnection.client.mediaUnitId,
|
|
188
|
+
peerConnectionId: this.peerConnection.peerConnectionId,
|
|
189
|
+
...sample,
|
|
190
|
+
timestamp,
|
|
191
|
+
sampleSeq: -1,
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
if (this.kind === 'audio') this.reports.addInboundAudioTrackReport(report);
|
|
195
|
+
else if (this.kind === 'video') this.reports.addInboundVideoTrackReport(report);
|
|
196
|
+
|
|
197
|
+
if (!this._model.sfuStreamId && sample.sfuStreamId) {
|
|
198
|
+
this._model.sfuStreamId = sample.sfuStreamId;
|
|
199
|
+
executeSave = true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!this._model.sfuSinkId && sample.sfuSinkId) {
|
|
203
|
+
this._model.sfuSinkId = sample.sfuSinkId;
|
|
204
|
+
executeSave = true;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const elapsedTimeInMs = Math.max(1, timestamp - this._updated);
|
|
208
|
+
const lastStat = this._stats.get(sample.ssrc);
|
|
209
|
+
const rttInMs = sample.roundTripTime ? sample.roundTripTime * 1000 : undefined;
|
|
210
|
+
const bitrate = ((sample.bytesReceived ?? 0) - (lastStat?.bytesReceived ?? 0)) * 8 / (elapsedTimeInMs / 1000);
|
|
211
|
+
const lostPackets = (sample.packetsLost ?? 0) - (lastStat?.packetsLost ?? 0);
|
|
212
|
+
const receivedPackets = (sample.packetsReceived ?? 0) - (lastStat?.packetsReceived ?? 0);
|
|
213
|
+
const fractionLost = 0 < receivedPackets && 0 < lostPackets ? (lostPackets / (receivedPackets + lostPackets)) : 0;
|
|
214
|
+
const stats: ObservedInboundTrackStats<Kind> = {
|
|
215
|
+
...sample,
|
|
216
|
+
fractionLost,
|
|
217
|
+
rttInMs,
|
|
218
|
+
bitrate,
|
|
219
|
+
ssrc: sample.ssrc,
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
this._stats.set(sample.ssrc, stats);
|
|
223
|
+
|
|
224
|
+
this.bitrate = [ ...this._stats.values() ].reduce((acc, stat) => acc + stat.bitrate, 0);
|
|
225
|
+
this.rttInMs = [ ...this._stats.values() ].reduce((acc, stat) => acc + (stat.rttInMs ?? 0), 0) / (this._stats.size || 1);
|
|
226
|
+
|
|
227
|
+
if (executeSave) await this._save();
|
|
228
|
+
|
|
229
|
+
this._updated = timestamp;
|
|
230
|
+
this.emit('update');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private async _save() {
|
|
234
|
+
if (this._closed) throw new Error(`OutboundTrack ${this.trackId} is closed`);
|
|
235
|
+
|
|
236
|
+
return this._storageProvider.inboundTrackStorage.set(this.trackId, this._model);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { StorageProvider } from './storages/StorageProvider';
|
|
3
|
+
import * as Models from './models/Models';
|
|
4
|
+
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
5
|
+
import { OutboundAudioTrack, OutboundVideoTrack } from '@observertc/sample-schemas-js';
|
|
6
|
+
import { ObservedInboundTrack } from './ObservedInboundTrack';
|
|
7
|
+
import { OutboundAudioTrackReport, OutboundVideoTrackReport } from '@observertc/report-schemas-js';
|
|
8
|
+
import { MediaKind } from './common/types';
|
|
9
|
+
import { createSingleExecutor } from './common/SingleExecutor';
|
|
10
|
+
|
|
11
|
+
export type ObservedOutboundTrackConfig<K extends MediaKind> = {
|
|
12
|
+
trackId: string;
|
|
13
|
+
kind: K;
|
|
14
|
+
sfuStreamId?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type ObservedOutboundTrackEvents = {
|
|
18
|
+
update: [],
|
|
19
|
+
close: [],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type ObservedOutboundTrackStatsUpdate<K extends MediaKind> = K extends 'audio' ? OutboundAudioTrack : OutboundVideoTrack;
|
|
23
|
+
|
|
24
|
+
export type ObservedOutboundTrackStats<K extends MediaKind> = ObservedOutboundTrackStatsUpdate<K> & {
|
|
25
|
+
ssrc: number;
|
|
26
|
+
bitrate: number;
|
|
27
|
+
rttInMs?: number;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// export type ObservedOutboundTrackStatsUpdate<K extends MediaKind> = {
|
|
31
|
+
// [Property in keyof ObservedOutboundTrackStats<K>]: ObservedOutboundTrackStats<K>[Property];
|
|
32
|
+
// }
|
|
33
|
+
|
|
34
|
+
export declare interface ObservedOutboundTrack<Kind extends MediaKind> {
|
|
35
|
+
on<U extends keyof ObservedOutboundTrackEvents>(event: U, listener: (...args: ObservedOutboundTrackEvents[U]) => void): this;
|
|
36
|
+
off<U extends keyof ObservedOutboundTrackEvents>(event: U, listener: (...args: ObservedOutboundTrackEvents[U]) => void): this;
|
|
37
|
+
once<U extends keyof ObservedOutboundTrackEvents>(event: U, listener: (...args: ObservedOutboundTrackEvents[U]) => void): this;
|
|
38
|
+
emit<U extends keyof ObservedOutboundTrackEvents>(event: U, ...args: ObservedOutboundTrackEvents[U]): boolean;
|
|
39
|
+
update(sample: ObservedOutboundTrackStatsUpdate<Kind>, timestamp: number): void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
43
|
+
public static async create<K extends MediaKind>(
|
|
44
|
+
config: ObservedOutboundTrackConfig<K>,
|
|
45
|
+
peerConnection: ObservedPeerConnection,
|
|
46
|
+
storageProvider: StorageProvider,
|
|
47
|
+
) {
|
|
48
|
+
const model = new Models.OutboundTrack({
|
|
49
|
+
serviceId: peerConnection.client.serviceId,
|
|
50
|
+
roomId: peerConnection.client.roomId,
|
|
51
|
+
callId: peerConnection.client.callId,
|
|
52
|
+
clientId: peerConnection.client.clientId,
|
|
53
|
+
mediaUnitId: peerConnection.client.mediaUnitId,
|
|
54
|
+
peerConnectionId: peerConnection.peerConnectionId,
|
|
55
|
+
trackId: config.trackId,
|
|
56
|
+
kind: config.kind,
|
|
57
|
+
sfuStreamId: config.sfuStreamId,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const alreadyInserted = await storageProvider.outboundTrackStorage.insert(config.trackId, model);
|
|
61
|
+
|
|
62
|
+
if (alreadyInserted) throw new Error(`OutboundAudioTrack with id ${config.trackId} already exists`);
|
|
63
|
+
|
|
64
|
+
return new ObservedOutboundTrack<K>(model, peerConnection, storageProvider);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public bitrate?: number;
|
|
68
|
+
public rttInMs?: number;
|
|
69
|
+
|
|
70
|
+
private readonly _stats = new Map<number, ObservedOutboundTrackStats<Kind>>();
|
|
71
|
+
private readonly _execute = createSingleExecutor();
|
|
72
|
+
|
|
73
|
+
private _closed = false;
|
|
74
|
+
private _updated = Date.now();
|
|
75
|
+
private _remoteInboundTracks = new Map<string, ObservedInboundTrack<Kind>>();
|
|
76
|
+
|
|
77
|
+
private constructor(
|
|
78
|
+
private readonly _model: Models.OutboundTrack,
|
|
79
|
+
public readonly peerConnection: ObservedPeerConnection,
|
|
80
|
+
private readonly _storageProvider: StorageProvider,
|
|
81
|
+
) {
|
|
82
|
+
super();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public get kind(): Kind {
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
87
|
+
return this._model.kind! as Kind;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public get trackId() {
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
92
|
+
return this._model.trackId!;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public get sfuStreamId() {
|
|
96
|
+
return this._model.sfuStreamId;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public get closed() {
|
|
100
|
+
return this._closed;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public get remoteInboundTracks(): ReadonlyMap<string, ObservedInboundTrack<Kind>> {
|
|
104
|
+
return this._remoteInboundTracks;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public get reports() {
|
|
108
|
+
return this.peerConnection.reports;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public get updated() {
|
|
112
|
+
return this._updated;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public close() {
|
|
116
|
+
if (this._closed) return;
|
|
117
|
+
|
|
118
|
+
this._closed = true;
|
|
119
|
+
|
|
120
|
+
this._execute(() => this._storageProvider.inboundTrackStorage.remove(this.trackId))
|
|
121
|
+
.catch(() => void 0)
|
|
122
|
+
.finally(() => this.emit('close'));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public get stats(): ReadonlyMap<number, ObservedOutboundTrackStats<Kind>> {
|
|
126
|
+
return this._stats;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public async update(sample: ObservedOutboundTrackStatsUpdate<Kind>, timestamp: number): Promise<void> {
|
|
130
|
+
if (this._closed) return;
|
|
131
|
+
let executeSave = false;
|
|
132
|
+
|
|
133
|
+
const report: OutboundAudioTrackReport | OutboundVideoTrackReport = {
|
|
134
|
+
serviceId: this.peerConnection.client.serviceId,
|
|
135
|
+
roomId: this.peerConnection.client.call.roomId,
|
|
136
|
+
callId: this.peerConnection.client.call.callId,
|
|
137
|
+
clientId: this.peerConnection.client.clientId,
|
|
138
|
+
userId: this.peerConnection.client.userId,
|
|
139
|
+
mediaUnitId: this.peerConnection.client.mediaUnitId,
|
|
140
|
+
peerConnectionId: this.peerConnection.peerConnectionId,
|
|
141
|
+
...sample,
|
|
142
|
+
timestamp,
|
|
143
|
+
sampleSeq: -1,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (this.kind === 'audio') this.reports.addOutboundAudioTrackReport(report);
|
|
147
|
+
else if (this.kind === 'video') this.reports.addOutboundVideoTrackReport(report);
|
|
148
|
+
|
|
149
|
+
const elapsedTimeInMs = Math.max(1, timestamp - this._updated);
|
|
150
|
+
const lastStat = this._stats.get(sample.ssrc);
|
|
151
|
+
const rttInMs = sample.roundTripTime ? sample.roundTripTime * 1000 : undefined;
|
|
152
|
+
const bitrate = ((sample.bytesSent ?? 0) - (lastStat?.bytesSent ?? 0)) * 8 / (elapsedTimeInMs / 1000);
|
|
153
|
+
// const lostPackets = (sample.packetsLost ?? 0) - (lastStat?.packetsLost ?? 0);
|
|
154
|
+
// const sentPackets = (sample.packetsSent ?? 0) - (lastStat?.packetsSent ?? 0);
|
|
155
|
+
const stats: ObservedOutboundTrackStats<Kind> = {
|
|
156
|
+
...sample,
|
|
157
|
+
rttInMs,
|
|
158
|
+
bitrate,
|
|
159
|
+
ssrc: sample.ssrc,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
this._stats.set(sample.ssrc, stats);
|
|
163
|
+
|
|
164
|
+
this.bitrate = [ ...this._stats.values() ].reduce((acc, stat) => acc + stat.bitrate, 0);
|
|
165
|
+
this.rttInMs = [ ...this._stats.values() ].reduce((acc, stat) => acc + (stat.rttInMs ?? 0), 0) / (this._stats.size || 1);
|
|
166
|
+
|
|
167
|
+
// setting up sfu connection as it is not always available at the first sample
|
|
168
|
+
if (sample.sfuStreamId && !this._model.sfuStreamId) {
|
|
169
|
+
this._model.sfuStreamId = sample.sfuStreamId;
|
|
170
|
+
|
|
171
|
+
this.once('close', () => {
|
|
172
|
+
if (!this._model.sfuStreamId) return;
|
|
173
|
+
if (this.kind === 'audio') this.peerConnection.client.call.sfuStreamIdToOutboundAudioTrack.delete(this._model.sfuStreamId);
|
|
174
|
+
else if (this.kind === 'video') this.peerConnection.client.call.sfuStreamIdToOutboundVideoTrack.delete(this._model.sfuStreamId);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
if (this.kind === 'audio') this.peerConnection.client.call.sfuStreamIdToOutboundAudioTrack.set(this._model.sfuStreamId, this as ObservedOutboundTrack<'audio'>);
|
|
178
|
+
else if (this.kind === 'video') this.peerConnection.client.call.sfuStreamIdToOutboundVideoTrack.set(this._model.sfuStreamId, this as ObservedOutboundTrack<'video'>);
|
|
179
|
+
|
|
180
|
+
executeSave = true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (executeSave) await this._save();
|
|
184
|
+
|
|
185
|
+
this._updated = timestamp;
|
|
186
|
+
this.emit('update');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
public connectInboundTrack(track: ObservedInboundTrack<Kind>) {
|
|
190
|
+
if (this._closed) return;
|
|
191
|
+
|
|
192
|
+
track.remoteOutboundTrack = this;
|
|
193
|
+
track.once('close', () => {
|
|
194
|
+
this._remoteInboundTracks.delete(track.trackId);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
this._remoteInboundTracks.set(track.trackId, track);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private async _save() {
|
|
201
|
+
if (this._closed) throw new Error(`OutboundTrack ${this.trackId} is closed`);
|
|
202
|
+
|
|
203
|
+
return this._storageProvider.outboundTrackStorage.set(this.trackId, this._model);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import * as Models from './models/Models';
|
|
3
|
+
import { StorageProvider } from './storages/StorageProvider';
|
|
4
|
+
import { PeerConnectionTransport } from '@observertc/sample-schemas-js';
|
|
5
|
+
import { ObservedClient } from './ObservedClient';
|
|
6
|
+
import { ObservedInboundTrack, ObservedInboundTrackConfig } from './ObservedInboundTrack';
|
|
7
|
+
import { ObservedOutboundTrack, ObservedOutboundTrackConfig } from './ObservedOutboundTrack';
|
|
8
|
+
import { PeerConnectionTransportReport } from '@observertc/report-schemas-js';
|
|
9
|
+
import { createSingleExecutor } from './common/SingleExecutor';
|
|
10
|
+
|
|
11
|
+
export type ObservedPeerConnectionEvents = {
|
|
12
|
+
update: [],
|
|
13
|
+
close: [],
|
|
14
|
+
newinboudaudiotrack: [ObservedInboundTrack<'audio'>],
|
|
15
|
+
newinboudvideotrack: [ObservedInboundTrack<'video'>],
|
|
16
|
+
newoutboundaudiotrack: [ObservedOutboundTrack<'audio'>],
|
|
17
|
+
newoutboundvideotrack: [ObservedOutboundTrack<'video'>],
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type ObservedPeerConnectionConfig = {
|
|
21
|
+
peerConnectionId: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type ObservedPeerConnectionStats = Omit<PeerConnectionTransport, 'transportId' | 'label'>;
|
|
25
|
+
|
|
26
|
+
export declare interface ObservedPeerConnection {
|
|
27
|
+
on<U extends keyof ObservedPeerConnectionEvents>(event: U, listener: (...args: ObservedPeerConnectionEvents[U]) => void): this;
|
|
28
|
+
off<U extends keyof ObservedPeerConnectionEvents>(event: U, listener: (...args: ObservedPeerConnectionEvents[U]) => void): this;
|
|
29
|
+
once<U extends keyof ObservedPeerConnectionEvents>(event: U, listener: (...args: ObservedPeerConnectionEvents[U]) => void): this;
|
|
30
|
+
emit<U extends keyof ObservedPeerConnectionEvents>(event: U, ...args: ObservedPeerConnectionEvents[U]): boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class ObservedPeerConnection extends EventEmitter {
|
|
34
|
+
public static async create(
|
|
35
|
+
config: ObservedPeerConnectionConfig,
|
|
36
|
+
client: ObservedClient,
|
|
37
|
+
storageProvider: StorageProvider,
|
|
38
|
+
): Promise<ObservedPeerConnection> {
|
|
39
|
+
const model = new Models.PeerConnection({
|
|
40
|
+
roomId: client.roomId,
|
|
41
|
+
serviceId: client.serviceId,
|
|
42
|
+
callId: client.callId,
|
|
43
|
+
clientId: client.clientId,
|
|
44
|
+
peerConnectionId: config.peerConnectionId,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const alreadyInserted = await storageProvider.peerConnectionStorage.insert(config.peerConnectionId, model);
|
|
48
|
+
|
|
49
|
+
if (alreadyInserted) throw new Error(`PeerConnection with id ${config.peerConnectionId} already exists`);
|
|
50
|
+
|
|
51
|
+
return new ObservedPeerConnection(model, client, storageProvider);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private _closed = false;
|
|
55
|
+
private _updated = Date.now();
|
|
56
|
+
private _sample?: ObservedPeerConnectionStats;
|
|
57
|
+
|
|
58
|
+
private readonly _inboundAudioTracks = new Map<string, ObservedInboundTrack<'audio'>>();
|
|
59
|
+
private readonly _inboundVideoTracks = new Map<string, ObservedInboundTrack<'video'>>();
|
|
60
|
+
private readonly _outboundAudioTracks = new Map<string, ObservedOutboundTrack<'audio'>>();
|
|
61
|
+
private readonly _outboundVideoTracks = new Map<string, ObservedOutboundTrack<'video'>>();
|
|
62
|
+
private readonly _execute = createSingleExecutor();
|
|
63
|
+
|
|
64
|
+
private constructor(
|
|
65
|
+
private readonly _model: Models.PeerConnection,
|
|
66
|
+
public readonly client: ObservedClient,
|
|
67
|
+
private readonly _storageProvider: StorageProvider,
|
|
68
|
+
) {
|
|
69
|
+
super();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public get peerConnectionId(): string {
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
74
|
+
return this._model.peerConnectionId!;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public get reports() {
|
|
78
|
+
return this.client.reports;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public get stats(): ObservedPeerConnectionStats | undefined {
|
|
82
|
+
return this._sample;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public get updated(): number {
|
|
86
|
+
return this._updated;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public get inboundAudioTracks(): ReadonlyMap<string, ObservedInboundTrack<'audio'>> {
|
|
90
|
+
return this._inboundAudioTracks;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public get inboundVideoTracks(): ReadonlyMap<string, ObservedInboundTrack<'video'>> {
|
|
94
|
+
return this._inboundVideoTracks;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public get outboundAudioTracks(): ReadonlyMap<string, ObservedOutboundTrack<'audio'>> {
|
|
98
|
+
return this._outboundAudioTracks;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public get outboundVideoTracks(): ReadonlyMap<string, ObservedOutboundTrack<'video'>> {
|
|
102
|
+
return this._outboundVideoTracks;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public get closed() {
|
|
106
|
+
return this._closed;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public close() {
|
|
110
|
+
if (this._closed) return;
|
|
111
|
+
this._closed = true;
|
|
112
|
+
|
|
113
|
+
Array.from(this._inboundAudioTracks.values()).forEach((track) => track.close());
|
|
114
|
+
Array.from(this._inboundVideoTracks.values()).forEach((track) => track.close());
|
|
115
|
+
Array.from(this._outboundAudioTracks.values()).forEach((track) => track.close());
|
|
116
|
+
Array.from(this._outboundVideoTracks.values()).forEach((track) => track.close());
|
|
117
|
+
|
|
118
|
+
this._execute(() => this._storageProvider.peerConnectionStorage.remove(this.peerConnectionId))
|
|
119
|
+
.catch(() => void 0)
|
|
120
|
+
.finally(() => this.emit('close'));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public update(sample: PeerConnectionTransport, timestamp: number) {
|
|
124
|
+
if (this._closed) return;
|
|
125
|
+
if (sample.peerConnectionId !== this._model.peerConnectionId) throw new Error(`TransportId mismatch. PeerConnectionId: ${ this._model.peerConnectionId } TransportId: ${ sample.transportId}`);
|
|
126
|
+
|
|
127
|
+
this._sample = sample;
|
|
128
|
+
|
|
129
|
+
const report: PeerConnectionTransportReport = {
|
|
130
|
+
serviceId: this.client.call.serviceId,
|
|
131
|
+
roomId: this.client.call.roomId,
|
|
132
|
+
callId: this.client.call.callId,
|
|
133
|
+
clientId: this.client.clientId,
|
|
134
|
+
userId: this.client.userId,
|
|
135
|
+
mediaUnitId: this.client.mediaUnitId,
|
|
136
|
+
...sample,
|
|
137
|
+
timestamp,
|
|
138
|
+
sampleSeq: -1, // deprecated
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
this.reports.addPeerConnectionTransportReports(report);
|
|
142
|
+
|
|
143
|
+
this._updated = timestamp;
|
|
144
|
+
this.emit('update');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public async createInboundAudioTrack(config: Omit<ObservedInboundTrackConfig<'audio'>, 'kind'>): Promise<ObservedInboundTrack<'audio'>> {
|
|
148
|
+
if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
|
|
149
|
+
|
|
150
|
+
const result = await ObservedInboundTrack.create<'audio'>({
|
|
151
|
+
kind: 'audio',
|
|
152
|
+
trackId: config.trackId,
|
|
153
|
+
}, this, this._storageProvider);
|
|
154
|
+
|
|
155
|
+
result.on('close', () => {
|
|
156
|
+
this._inboundAudioTracks.delete(result.trackId);
|
|
157
|
+
this._model.inboundTrackIds = this._model.inboundTrackIds.filter((id) => id !== result.trackId);
|
|
158
|
+
!this._closed &&this._save().catch(() => void 0);
|
|
159
|
+
});
|
|
160
|
+
this._inboundAudioTracks.set(result.trackId, result);
|
|
161
|
+
this._model.inboundTrackIds = [ ...(new Set<string>([ ...this._model.inboundTrackIds, result.trackId ])) ];
|
|
162
|
+
await this._save();
|
|
163
|
+
|
|
164
|
+
this.emit('newinboudaudiotrack', result);
|
|
165
|
+
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
public async createInboundVideoTrack(config: Omit<ObservedInboundTrackConfig<'video'>, 'kind'>): Promise<ObservedInboundTrack<'video'>> {
|
|
170
|
+
if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
|
|
171
|
+
|
|
172
|
+
const result = await ObservedInboundTrack.create<'video'>({
|
|
173
|
+
kind: 'video',
|
|
174
|
+
trackId: config.trackId,
|
|
175
|
+
}, this, this._storageProvider);
|
|
176
|
+
|
|
177
|
+
result.on('close', () => {
|
|
178
|
+
this._inboundVideoTracks.delete(result.trackId);
|
|
179
|
+
this._model.inboundTrackIds = this._model.inboundTrackIds.filter((id) => id !== result.trackId);
|
|
180
|
+
!this._closed &&this._save().catch(() => void 0);
|
|
181
|
+
});
|
|
182
|
+
this._inboundVideoTracks.set(result.trackId, result);
|
|
183
|
+
this._model.inboundTrackIds = [ ...(new Set<string>([ ...this._model.inboundTrackIds, result.trackId ])) ];
|
|
184
|
+
await this._save();
|
|
185
|
+
|
|
186
|
+
this.emit('newinboudvideotrack', result);
|
|
187
|
+
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
public async createOutboundAudioTrack(config: Omit<ObservedOutboundTrackConfig<'audio'>, 'kind'>): Promise<ObservedOutboundTrack<'audio'>> {
|
|
192
|
+
if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
|
|
193
|
+
|
|
194
|
+
const result = await ObservedOutboundTrack.create<'audio'>({
|
|
195
|
+
kind: 'audio',
|
|
196
|
+
trackId: config.trackId,
|
|
197
|
+
}, this, this._storageProvider);
|
|
198
|
+
|
|
199
|
+
result.on('close', () => {
|
|
200
|
+
this._outboundAudioTracks.delete(result.trackId);
|
|
201
|
+
this._model.outboundTrackIds = this._model.outboundTrackIds.filter((id) => id !== result.trackId);
|
|
202
|
+
|
|
203
|
+
result.sfuStreamId && this.client.call.sfuStreamIdToOutboundAudioTrack.delete(result.sfuStreamId);
|
|
204
|
+
!this._closed &&this._save().catch(() => void 0);
|
|
205
|
+
});
|
|
206
|
+
this._outboundAudioTracks.set(result.trackId, result);
|
|
207
|
+
this._model.outboundTrackIds = [ ...(new Set<string>([ ...this._model.outboundTrackIds, result.trackId ])) ];
|
|
208
|
+
|
|
209
|
+
result.sfuStreamId && this.client.call.sfuStreamIdToOutboundAudioTrack.set(result.sfuStreamId, result);
|
|
210
|
+
await this._save();
|
|
211
|
+
|
|
212
|
+
this.emit('newoutboundaudiotrack', result);
|
|
213
|
+
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
public async createOutboundVideoTrack(config: Omit<ObservedOutboundTrackConfig<'video'>, 'kind'>): Promise<ObservedOutboundTrack<'video'>> {
|
|
218
|
+
if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
|
|
219
|
+
|
|
220
|
+
const result = await ObservedOutboundTrack.create<'video'>({
|
|
221
|
+
kind: 'video',
|
|
222
|
+
trackId: config.trackId,
|
|
223
|
+
}, this, this._storageProvider);
|
|
224
|
+
|
|
225
|
+
result.on('close', () => {
|
|
226
|
+
this._outboundVideoTracks.delete(result.trackId);
|
|
227
|
+
result.sfuStreamId && this.client.call.sfuStreamIdToOutboundVideoTrack.set(result.sfuStreamId, result);
|
|
228
|
+
this._model.outboundTrackIds = this._model.outboundTrackIds.filter((id) => id !== result.trackId);
|
|
229
|
+
!this._closed && this._save().catch(() => void 0);
|
|
230
|
+
});
|
|
231
|
+
this._outboundVideoTracks.set(result.trackId, result);
|
|
232
|
+
result.sfuStreamId && this.client.call.sfuStreamIdToOutboundVideoTrack.set(result.sfuStreamId, result);
|
|
233
|
+
this._model.outboundTrackIds = [ ...(new Set<string>([ ...this._model.outboundTrackIds, result.trackId ])) ];
|
|
234
|
+
await this._save();
|
|
235
|
+
|
|
236
|
+
this.emit('newoutboundvideotrack', result);
|
|
237
|
+
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private async _save() {
|
|
242
|
+
if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
|
|
243
|
+
|
|
244
|
+
return this._execute(async () => {
|
|
245
|
+
if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
|
|
246
|
+
await this._storageProvider.peerConnectionStorage.set(this.peerConnectionId, this._model);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|