@stream-io/video-client 1.27.0 → 1.27.1
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/CHANGELOG.md +8 -0
- package/dist/index.browser.es.js +43 -28
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +42 -27
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +43 -28
- package/dist/index.es.js.map +1 -1
- package/dist/src/devices/devices.d.ts +5 -5
- package/dist/src/helpers/lazy.d.ts +1 -1
- package/dist/src/stats/rtc/Tracer.d.ts +4 -1
- package/dist/src/stats/rtc/types.d.ts +1 -0
- package/dist/src/timers/index.d.ts +1 -1
- package/package.json +2 -2
- package/src/Call.ts +7 -4
- package/src/coordinator/connection/connection.ts +0 -1
- package/src/devices/CameraManager.ts +1 -1
- package/src/devices/InputMediaDeviceManager.ts +5 -3
- package/src/devices/MicrophoneManager.ts +2 -1
- package/src/devices/SpeakerManager.ts +1 -1
- package/src/devices/devices.ts +29 -11
- package/src/helpers/lazy.ts +3 -3
- package/src/rtc/__tests__/videoLayers.test.ts +4 -6
- package/src/rtc/videoLayers.ts +12 -6
- package/src/stats/rtc/Tracer.ts +19 -1
- package/src/stats/rtc/types.ts +1 -0
|
@@ -9,33 +9,33 @@ export declare const checkIfAudioOutputChangeSupported: () => boolean;
|
|
|
9
9
|
* Keeps track of the browser permission to use microphone. This permission also
|
|
10
10
|
* affects an ability to enumerate audio devices.
|
|
11
11
|
*/
|
|
12
|
-
export declare const getAudioBrowserPermission: () => BrowserPermission;
|
|
12
|
+
export declare const getAudioBrowserPermission: (...args: never[]) => BrowserPermission;
|
|
13
13
|
/**
|
|
14
14
|
* Keeps track of the browser permission to use camera. This permission also
|
|
15
15
|
* affects an ability to enumerate video devices.
|
|
16
16
|
*/
|
|
17
|
-
export declare const getVideoBrowserPermission: () => BrowserPermission;
|
|
17
|
+
export declare const getVideoBrowserPermission: (...args: never[]) => BrowserPermission;
|
|
18
18
|
/**
|
|
19
19
|
* Prompts the user for a permission to use audio devices (if not already granted
|
|
20
20
|
* and was not prompted before) and lists the available 'audioinput' devices,
|
|
21
21
|
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
22
22
|
* the observable errors.
|
|
23
23
|
*/
|
|
24
|
-
export declare const getAudioDevices: () => import("rxjs").Observable<MediaDeviceInfo[]>;
|
|
24
|
+
export declare const getAudioDevices: (...args: (Tracer | undefined)[]) => import("rxjs").Observable<MediaDeviceInfo[]>;
|
|
25
25
|
/**
|
|
26
26
|
* Prompts the user for a permission to use video devices (if not already granted
|
|
27
27
|
* and was not prompted before) and lists the available 'videoinput' devices,
|
|
28
28
|
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
29
29
|
* the observable errors.
|
|
30
30
|
*/
|
|
31
|
-
export declare const getVideoDevices: () => import("rxjs").Observable<MediaDeviceInfo[]>;
|
|
31
|
+
export declare const getVideoDevices: (...args: (Tracer | undefined)[]) => import("rxjs").Observable<MediaDeviceInfo[]>;
|
|
32
32
|
/**
|
|
33
33
|
* Prompts the user for a permission to use video devices (if not already granted
|
|
34
34
|
* and was not prompted before) and lists the available 'audiooutput' devices,
|
|
35
35
|
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
36
36
|
* the observable errors.
|
|
37
37
|
*/
|
|
38
|
-
export declare const getAudioOutputDevices: () => import("rxjs").Observable<MediaDeviceInfo[]>;
|
|
38
|
+
export declare const getAudioOutputDevices: (...args: (Tracer | undefined)[]) => import("rxjs").Observable<MediaDeviceInfo[]>;
|
|
39
39
|
/**
|
|
40
40
|
* Returns an audio media stream that fulfills the given constraints.
|
|
41
41
|
* If no constraints are provided, it uses the browser's default ones.
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import type { Trace, TraceSlice } from './types';
|
|
1
|
+
import type { RTCStatsDataType, Trace, TraceKey, TraceSlice } from './types';
|
|
2
2
|
export declare class Tracer {
|
|
3
3
|
private buffer;
|
|
4
4
|
private enabled;
|
|
5
5
|
private readonly id;
|
|
6
|
+
private keys?;
|
|
6
7
|
constructor(id: string | null);
|
|
7
8
|
setEnabled: (enabled: boolean) => void;
|
|
8
9
|
trace: Trace;
|
|
10
|
+
traceOnce: (key: TraceKey, tag: string, data: RTCStatsDataType) => void;
|
|
11
|
+
resetTrace: (key: TraceKey) => void;
|
|
9
12
|
take: () => TraceSlice;
|
|
10
13
|
dispose: () => void;
|
|
11
14
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PerformanceStats } from '../../gen/video/sfu/models/models';
|
|
2
2
|
export type RTCStatsDataType = RTCConfiguration | RTCIceCandidate | RTCSignalingState | RTCIceConnectionState | RTCIceGatheringState | RTCPeerConnectionState | [number | null | string] | string | boolean | RTCOfferOptions | [string | RTCDataChannelInit | undefined] | (RTCOfferOptions | undefined) | RTCSessionDescriptionInit | (RTCIceCandidateInit | RTCIceCandidate) | object | null | undefined;
|
|
3
|
+
export type TraceKey = 'device-enumeration' | (string & {});
|
|
3
4
|
export type Trace = (tag: string, data: RTCStatsDataType) => void;
|
|
4
5
|
export type TraceRecord = [
|
|
5
6
|
tag: string,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stream-io/video-client",
|
|
3
|
-
"version": "1.27.
|
|
3
|
+
"version": "1.27.1",
|
|
4
4
|
"main": "dist/index.cjs.js",
|
|
5
5
|
"module": "dist/index.es.js",
|
|
6
6
|
"browser": "dist/index.browser.es.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@openapitools/openapi-generator-cli": "^2.13.4",
|
|
41
41
|
"@rollup/plugin-replace": "^6.0.2",
|
|
42
42
|
"@rollup/plugin-typescript": "^12.1.2",
|
|
43
|
-
"@stream-io/audio-filters-web": "^0.4.
|
|
43
|
+
"@stream-io/audio-filters-web": "^0.4.3",
|
|
44
44
|
"@stream-io/node-sdk": "^0.4.24",
|
|
45
45
|
"@types/sdp-transform": "^2.4.9",
|
|
46
46
|
"@types/ua-parser-js": "^0.7.39",
|
package/src/Call.ts
CHANGED
|
@@ -1884,10 +1884,13 @@ export class Call {
|
|
|
1884
1884
|
* @internal
|
|
1885
1885
|
*/
|
|
1886
1886
|
notifyTrackMuteState = async (muted: boolean, ...trackTypes: TrackType[]) => {
|
|
1887
|
-
|
|
1888
|
-
await
|
|
1889
|
-
|
|
1890
|
-
|
|
1887
|
+
const key = `muteState.${this.cid}.${trackTypes.join('-')}`;
|
|
1888
|
+
await withoutConcurrency(key, async () => {
|
|
1889
|
+
if (!this.sfuClient) return;
|
|
1890
|
+
await this.sfuClient.updateMuteStates(
|
|
1891
|
+
trackTypes.map((trackType) => ({ trackType, muted })),
|
|
1892
|
+
);
|
|
1893
|
+
});
|
|
1891
1894
|
};
|
|
1892
1895
|
|
|
1893
1896
|
/**
|
|
@@ -580,7 +580,6 @@ export class StableWSConnection {
|
|
|
580
580
|
this.totalFailures += 1;
|
|
581
581
|
this._setHealth(false);
|
|
582
582
|
this.isConnecting = false;
|
|
583
|
-
this.rejectConnectionOpen?.(new Error(`WebSocket error: ${event}`));
|
|
584
583
|
this._log(`onerror() - WS connection resulted into error`, { event });
|
|
585
584
|
|
|
586
585
|
this._reconnect();
|
|
@@ -149,7 +149,7 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
protected getDevices(): Observable<MediaDeviceInfo[]> {
|
|
152
|
-
return getVideoDevices();
|
|
152
|
+
return getVideoDevices(this.call.tracer);
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
protected getStream(
|
|
@@ -198,6 +198,10 @@ export abstract class InputMediaDeviceManager<
|
|
|
198
198
|
entry.stop?.();
|
|
199
199
|
this.filters = this.filters.filter((f) => f !== entry);
|
|
200
200
|
await this.applySettingsToStream();
|
|
201
|
+
this.call.tracer.trace(
|
|
202
|
+
`unregisterFilter.${TrackType[this.trackType]}`,
|
|
203
|
+
null,
|
|
204
|
+
);
|
|
201
205
|
}),
|
|
202
206
|
};
|
|
203
207
|
}
|
|
@@ -219,9 +223,7 @@ export abstract class InputMediaDeviceManager<
|
|
|
219
223
|
*/
|
|
220
224
|
async select(deviceId: string | undefined) {
|
|
221
225
|
if (isReactNative()) {
|
|
222
|
-
throw new Error(
|
|
223
|
-
'This method is not supported in React Native. Please visit https://getstream.io/video/docs/reactnative/core/camera-and-microphone/#speaker-management for reference.',
|
|
224
|
-
);
|
|
226
|
+
throw new Error('This method is not supported in React Native.');
|
|
225
227
|
}
|
|
226
228
|
const prevDeviceId = this.state.selectedDevice;
|
|
227
229
|
if (deviceId === prevDeviceId) {
|
|
@@ -195,6 +195,7 @@ export class MicrophoneManager extends InputMediaDeviceManager<MicrophoneManager
|
|
|
195
195
|
this.logger('warn', 'Failed to unregister noise cancellation', err);
|
|
196
196
|
});
|
|
197
197
|
|
|
198
|
+
this.call.tracer.trace('noiseCancellation.disabled', true);
|
|
198
199
|
await this.call.notifyNoiseCancellationStopped();
|
|
199
200
|
}
|
|
200
201
|
|
|
@@ -245,7 +246,7 @@ export class MicrophoneManager extends InputMediaDeviceManager<MicrophoneManager
|
|
|
245
246
|
}
|
|
246
247
|
|
|
247
248
|
protected getDevices(): Observable<MediaDeviceInfo[]> {
|
|
248
|
-
return getAudioDevices();
|
|
249
|
+
return getAudioDevices(this.call.tracer);
|
|
249
250
|
}
|
|
250
251
|
|
|
251
252
|
protected getStream(
|
|
@@ -56,7 +56,7 @@ export class SpeakerManager {
|
|
|
56
56
|
'This feature is not supported in React Native. Please visit https://getstream.io/video/docs/reactnative/core/camera-and-microphone/#speaker-management for more details',
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
|
-
return getAudioOutputDevices();
|
|
59
|
+
return getAudioOutputDevices(this.call.tracer);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/**
|
package/src/devices/devices.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
merge,
|
|
8
8
|
shareReplay,
|
|
9
9
|
startWith,
|
|
10
|
+
tap,
|
|
10
11
|
} from 'rxjs';
|
|
11
12
|
import { getLogger } from '../logger';
|
|
12
13
|
import { BrowserPermission } from './BrowserPermission';
|
|
@@ -21,8 +22,13 @@ import { getCurrentValue } from '../store/rxUtils';
|
|
|
21
22
|
*
|
|
22
23
|
* @param permission a BrowserPermission instance.
|
|
23
24
|
* @param kind the kind of devices to enumerate.
|
|
25
|
+
* @param tracer the tracer to use for tracing the device enumeration.
|
|
24
26
|
*/
|
|
25
|
-
const getDevices = (
|
|
27
|
+
const getDevices = (
|
|
28
|
+
permission: BrowserPermission,
|
|
29
|
+
kind: MediaDeviceKind,
|
|
30
|
+
tracer: Tracer | undefined,
|
|
31
|
+
) => {
|
|
26
32
|
return from(
|
|
27
33
|
(async () => {
|
|
28
34
|
let devices = await navigator.mediaDevices.enumerateDevices();
|
|
@@ -34,6 +40,11 @@ const getDevices = (permission: BrowserPermission, kind: MediaDeviceKind) => {
|
|
|
34
40
|
if (shouldPromptForBrowserPermission && (await permission.prompt())) {
|
|
35
41
|
devices = await navigator.mediaDevices.enumerateDevices();
|
|
36
42
|
}
|
|
43
|
+
tracer?.traceOnce(
|
|
44
|
+
'device-enumeration',
|
|
45
|
+
'navigator.mediaDevices.enumerateDevices',
|
|
46
|
+
devices,
|
|
47
|
+
);
|
|
37
48
|
return devices.filter(
|
|
38
49
|
(device) =>
|
|
39
50
|
device.kind === kind &&
|
|
@@ -99,11 +110,12 @@ export const getVideoBrowserPermission = lazy(
|
|
|
99
110
|
}),
|
|
100
111
|
);
|
|
101
112
|
|
|
102
|
-
const getDeviceChangeObserver = lazy(() => {
|
|
113
|
+
const getDeviceChangeObserver = lazy((tracer: Tracer | undefined) => {
|
|
103
114
|
// 'addEventListener' is not available in React Native, returning
|
|
104
115
|
// an observable that will never fire
|
|
105
116
|
if (!navigator.mediaDevices.addEventListener) return from([]);
|
|
106
117
|
return fromEvent(navigator.mediaDevices, 'devicechange').pipe(
|
|
118
|
+
tap(() => tracer?.resetTrace('device-enumeration')),
|
|
107
119
|
map(() => undefined),
|
|
108
120
|
debounceTime(500),
|
|
109
121
|
);
|
|
@@ -115,13 +127,15 @@ const getDeviceChangeObserver = lazy(() => {
|
|
|
115
127
|
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
116
128
|
* the observable errors.
|
|
117
129
|
*/
|
|
118
|
-
export const getAudioDevices = lazy(() => {
|
|
130
|
+
export const getAudioDevices = lazy((tracer?: Tracer) => {
|
|
119
131
|
return merge(
|
|
120
|
-
getDeviceChangeObserver(),
|
|
132
|
+
getDeviceChangeObserver(tracer),
|
|
121
133
|
getAudioBrowserPermission().asObservable(),
|
|
122
134
|
).pipe(
|
|
123
135
|
startWith(undefined),
|
|
124
|
-
concatMap(() =>
|
|
136
|
+
concatMap(() =>
|
|
137
|
+
getDevices(getAudioBrowserPermission(), 'audioinput', tracer),
|
|
138
|
+
),
|
|
125
139
|
shareReplay(1),
|
|
126
140
|
);
|
|
127
141
|
});
|
|
@@ -132,13 +146,15 @@ export const getAudioDevices = lazy(() => {
|
|
|
132
146
|
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
133
147
|
* the observable errors.
|
|
134
148
|
*/
|
|
135
|
-
export const getVideoDevices = lazy(() => {
|
|
149
|
+
export const getVideoDevices = lazy((tracer?: Tracer) => {
|
|
136
150
|
return merge(
|
|
137
|
-
getDeviceChangeObserver(),
|
|
151
|
+
getDeviceChangeObserver(tracer),
|
|
138
152
|
getVideoBrowserPermission().asObservable(),
|
|
139
153
|
).pipe(
|
|
140
154
|
startWith(undefined),
|
|
141
|
-
concatMap(() =>
|
|
155
|
+
concatMap(() =>
|
|
156
|
+
getDevices(getVideoBrowserPermission(), 'videoinput', tracer),
|
|
157
|
+
),
|
|
142
158
|
shareReplay(1),
|
|
143
159
|
);
|
|
144
160
|
});
|
|
@@ -149,13 +165,15 @@ export const getVideoDevices = lazy(() => {
|
|
|
149
165
|
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
150
166
|
* the observable errors.
|
|
151
167
|
*/
|
|
152
|
-
export const getAudioOutputDevices = lazy(() => {
|
|
168
|
+
export const getAudioOutputDevices = lazy((tracer?: Tracer) => {
|
|
153
169
|
return merge(
|
|
154
|
-
getDeviceChangeObserver(),
|
|
170
|
+
getDeviceChangeObserver(tracer),
|
|
155
171
|
getAudioBrowserPermission().asObservable(),
|
|
156
172
|
).pipe(
|
|
157
173
|
startWith(undefined),
|
|
158
|
-
concatMap(() =>
|
|
174
|
+
concatMap(() =>
|
|
175
|
+
getDevices(getAudioBrowserPermission(), 'audiooutput', tracer),
|
|
176
|
+
),
|
|
159
177
|
shareReplay(1),
|
|
160
178
|
);
|
|
161
179
|
});
|
package/src/helpers/lazy.ts
CHANGED
|
@@ -3,11 +3,11 @@ const uninitialized = Symbol('uninitialized');
|
|
|
3
3
|
/**
|
|
4
4
|
* Lazily creates a value using a provided factory
|
|
5
5
|
*/
|
|
6
|
-
export function lazy<T>(factory: () => T): () => T {
|
|
6
|
+
export function lazy<T, A>(factory: (...args: A[]) => T): (...args: A[]) => T {
|
|
7
7
|
let value: T | typeof uninitialized = uninitialized;
|
|
8
|
-
return () => {
|
|
8
|
+
return (...args: A[]) => {
|
|
9
9
|
if (value === uninitialized) {
|
|
10
|
-
value = factory();
|
|
10
|
+
value = factory(...args);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
return value;
|
|
@@ -74,24 +74,22 @@ describe('videoLayers', () => {
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
it('should use predefined bitrate values when track dimensions cant be determined', () => {
|
|
77
|
-
const width = 0;
|
|
78
|
-
const height = 0;
|
|
79
77
|
const bitrate = 3000000;
|
|
80
78
|
const track = new MediaStreamTrack();
|
|
81
|
-
vi.spyOn(track, 'getSettings').mockReturnValue({
|
|
79
|
+
vi.spyOn(track, 'getSettings').mockReturnValue({});
|
|
82
80
|
const layers = computeVideoLayers(track, {
|
|
83
81
|
bitrate,
|
|
84
82
|
// @ts-expect-error - incomplete data
|
|
85
83
|
codec: { name: 'vp8' },
|
|
86
84
|
fps: 30,
|
|
87
|
-
videoDimension: { width, height },
|
|
85
|
+
videoDimension: { width: 320, height: 180 },
|
|
88
86
|
});
|
|
89
87
|
expect(layers).toEqual([
|
|
90
88
|
{
|
|
91
89
|
active: true,
|
|
92
90
|
rid: 'q',
|
|
93
|
-
width:
|
|
94
|
-
height:
|
|
91
|
+
width: 320,
|
|
92
|
+
height: 180,
|
|
95
93
|
maxBitrate: bitrate,
|
|
96
94
|
scaleResolutionDownBy: 1,
|
|
97
95
|
maxFramerate: 30,
|
package/src/rtc/videoLayers.ts
CHANGED
|
@@ -84,17 +84,17 @@ export const computeVideoLayers = (
|
|
|
84
84
|
): OptimalVideoLayer[] | undefined => {
|
|
85
85
|
if (isAudioTrackType(publishOption.trackType)) return;
|
|
86
86
|
const optimalVideoLayers: OptimalVideoLayer[] = [];
|
|
87
|
-
const settings = videoTrack.getSettings();
|
|
88
|
-
const { width = 0, height = 0 } = settings;
|
|
89
87
|
const {
|
|
90
88
|
bitrate,
|
|
91
89
|
codec,
|
|
92
|
-
fps,
|
|
90
|
+
fps = 30,
|
|
93
91
|
maxSpatialLayers = 3,
|
|
94
92
|
maxTemporalLayers = 3,
|
|
95
93
|
videoDimension = { width: 1280, height: 720 },
|
|
96
94
|
useSingleLayer,
|
|
97
95
|
} = publishOption;
|
|
96
|
+
const { width = videoDimension.width, height = videoDimension.height } =
|
|
97
|
+
videoTrack.getSettings();
|
|
98
98
|
const maxBitrate = getComputedMaxBitrate(
|
|
99
99
|
videoDimension,
|
|
100
100
|
width,
|
|
@@ -137,7 +137,12 @@ export const computeVideoLayers = (
|
|
|
137
137
|
|
|
138
138
|
// for simplicity, we start with all layers enabled, then this function
|
|
139
139
|
// will clear/reassign the layers that are not needed
|
|
140
|
-
return withSimulcastConstraints(
|
|
140
|
+
return withSimulcastConstraints(
|
|
141
|
+
width,
|
|
142
|
+
height,
|
|
143
|
+
optimalVideoLayers,
|
|
144
|
+
useSingleLayer,
|
|
145
|
+
);
|
|
141
146
|
};
|
|
142
147
|
|
|
143
148
|
/**
|
|
@@ -179,13 +184,14 @@ export const getComputedMaxBitrate = (
|
|
|
179
184
|
* https://chromium.googlesource.com/external/webrtc/+/refs/heads/main/media/engine/simulcast.cc#90
|
|
180
185
|
*/
|
|
181
186
|
const withSimulcastConstraints = (
|
|
182
|
-
|
|
187
|
+
width: number,
|
|
188
|
+
height: number,
|
|
183
189
|
optimalVideoLayers: OptimalVideoLayer[],
|
|
184
190
|
useSingleLayer: boolean,
|
|
185
191
|
) => {
|
|
186
192
|
let layers: OptimalVideoLayer[];
|
|
187
193
|
|
|
188
|
-
const size = Math.max(
|
|
194
|
+
const size = Math.max(width, height);
|
|
189
195
|
if (size <= 320) {
|
|
190
196
|
// provide only one layer 320x240 (f), the one with the highest quality
|
|
191
197
|
layers = optimalVideoLayers.filter((layer) => layer.rid === 'f');
|
package/src/stats/rtc/Tracer.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
RTCStatsDataType,
|
|
3
|
+
Trace,
|
|
4
|
+
TraceKey,
|
|
5
|
+
TraceRecord,
|
|
6
|
+
TraceSlice,
|
|
7
|
+
} from './types';
|
|
2
8
|
|
|
3
9
|
export class Tracer {
|
|
4
10
|
private buffer: TraceRecord[] = [];
|
|
5
11
|
private enabled = true;
|
|
6
12
|
private readonly id: string | null;
|
|
13
|
+
private keys?: Map<TraceKey, boolean>;
|
|
7
14
|
|
|
8
15
|
constructor(id: string | null) {
|
|
9
16
|
this.id = id;
|
|
@@ -20,6 +27,16 @@ export class Tracer {
|
|
|
20
27
|
this.buffer.push([tag, this.id, data, Date.now()]);
|
|
21
28
|
};
|
|
22
29
|
|
|
30
|
+
traceOnce = (key: TraceKey, tag: string, data: RTCStatsDataType) => {
|
|
31
|
+
if (this.keys?.has(key)) return;
|
|
32
|
+
this.trace(tag, data);
|
|
33
|
+
(this.keys ??= new Map()).set(key, true);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
resetTrace = (key: TraceKey) => {
|
|
37
|
+
this.keys?.delete(key);
|
|
38
|
+
};
|
|
39
|
+
|
|
23
40
|
take = (): TraceSlice => {
|
|
24
41
|
const snapshot = this.buffer;
|
|
25
42
|
this.buffer = [];
|
|
@@ -33,5 +50,6 @@ export class Tracer {
|
|
|
33
50
|
|
|
34
51
|
dispose = () => {
|
|
35
52
|
this.buffer = [];
|
|
53
|
+
this.keys?.clear();
|
|
36
54
|
};
|
|
37
55
|
}
|
package/src/stats/rtc/types.ts
CHANGED