@stream-io/video-client 1.20.2 → 1.22.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/CHANGELOG.md +19 -0
- package/dist/index.browser.es.js +521 -285
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +521 -285
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.es.js +521 -285
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +3 -0
- package/dist/src/StreamSfuClient.d.ts +1 -1
- package/dist/src/devices/InputMediaDeviceManager.d.ts +3 -3
- package/dist/src/devices/InputMediaDeviceManagerState.d.ts +0 -20
- package/dist/src/devices/SpeakerState.d.ts +3 -21
- package/dist/src/devices/devices.d.ts +8 -8
- package/dist/src/events/call.d.ts +1 -1
- package/dist/src/gen/video/sfu/models/models.d.ts +50 -0
- package/dist/src/gen/video/sfu/signal_rpc/signal.d.ts +29 -3
- package/dist/src/rpc/createClient.d.ts +1 -1
- package/dist/src/rtc/BasePeerConnection.d.ts +13 -7
- package/dist/src/rtc/Publisher.d.ts +4 -4
- package/dist/src/stats/CallStateStatsReporter.d.ts +5 -3
- package/dist/src/stats/SfuStatsReporter.d.ts +8 -1
- package/dist/src/stats/rtc/StatsTracer.d.ts +54 -0
- package/dist/src/stats/rtc/Tracer.d.ts +1 -5
- package/dist/src/stats/rtc/index.d.ts +2 -0
- package/dist/src/stats/rtc/types.d.ts +19 -0
- package/dist/src/stats/types.d.ts +13 -0
- package/dist/src/stats/utils.d.ts +14 -0
- package/index.ts +0 -4
- package/package.json +10 -10
- package/src/Call.ts +15 -4
- package/src/StreamSfuClient.ts +30 -18
- package/src/devices/CameraManager.ts +27 -23
- package/src/devices/CameraManagerState.ts +3 -2
- package/src/devices/InputMediaDeviceManager.ts +8 -5
- package/src/devices/InputMediaDeviceManagerState.ts +10 -31
- package/src/devices/MicrophoneManager.ts +1 -1
- package/src/devices/MicrophoneManagerState.ts +3 -2
- package/src/devices/ScreenShareManager.ts +2 -2
- package/src/devices/ScreenShareState.ts +5 -4
- package/src/devices/SpeakerManager.ts +2 -1
- package/src/devices/SpeakerState.ts +11 -27
- package/src/devices/__tests__/CameraManager.test.ts +43 -27
- package/src/devices/__tests__/MicrophoneManager.test.ts +5 -3
- package/src/devices/__tests__/ScreenShareManager.test.ts +5 -1
- package/src/devices/__tests__/mocks.ts +2 -3
- package/src/devices/devices.ts +38 -16
- package/src/events/__tests__/call.test.ts +23 -0
- package/src/events/call.ts +12 -1
- package/src/gen/video/sfu/models/models.ts +84 -0
- package/src/gen/video/sfu/signal_rpc/signal.ts +50 -2
- package/src/helpers/DynascaleManager.ts +0 -9
- package/src/rpc/createClient.ts +1 -1
- package/src/rtc/BasePeerConnection.ts +43 -16
- package/src/rtc/Publisher.ts +18 -16
- package/src/rtc/Subscriber.ts +2 -0
- package/src/rtc/__tests__/Publisher.test.ts +19 -0
- package/src/rtc/__tests__/Subscriber.test.ts +15 -1
- package/src/stats/CallStateStatsReporter.ts +19 -31
- package/src/stats/SfuStatsReporter.ts +45 -16
- package/src/stats/rtc/StatsTracer.ts +289 -0
- package/src/stats/rtc/Tracer.ts +1 -6
- package/src/stats/rtc/__tests__/Tracer.test.ts +57 -0
- package/src/stats/rtc/index.ts +3 -0
- package/src/stats/rtc/pc.ts +6 -76
- package/src/stats/rtc/types.ts +22 -0
- package/src/stats/types.ts +15 -0
- package/src/stats/utils.ts +15 -0
- package/dist/src/stats/rtc/mediaDevices.d.ts +0 -2
- package/src/stats/rtc/mediaDevices.ts +0 -42
|
@@ -14,6 +14,7 @@ import { TrackType } from '../../gen/video/sfu/models/models';
|
|
|
14
14
|
import { CameraManager } from '../CameraManager';
|
|
15
15
|
import { of } from 'rxjs';
|
|
16
16
|
import { PermissionsContext } from '../../permissions';
|
|
17
|
+
import { Tracer } from '../../stats';
|
|
17
18
|
|
|
18
19
|
const getVideoStream = vi.hoisted(() =>
|
|
19
20
|
vi.fn(() => Promise.resolve(mockVideoStream())),
|
|
@@ -78,11 +79,14 @@ describe('CameraManager', () => {
|
|
|
78
79
|
it('get stream', async () => {
|
|
79
80
|
await manager.enable();
|
|
80
81
|
|
|
81
|
-
expect(getVideoStream).toHaveBeenCalledWith(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
expect(getVideoStream).toHaveBeenCalledWith(
|
|
83
|
+
{
|
|
84
|
+
deviceId: undefined,
|
|
85
|
+
width: 1280,
|
|
86
|
+
height: 720,
|
|
87
|
+
},
|
|
88
|
+
expect.any(Tracer),
|
|
89
|
+
);
|
|
86
90
|
});
|
|
87
91
|
|
|
88
92
|
it('should get device id from stream', async () => {
|
|
@@ -133,29 +137,38 @@ describe('CameraManager', () => {
|
|
|
133
137
|
|
|
134
138
|
await manager.enable();
|
|
135
139
|
|
|
136
|
-
expect(getVideoStream).toHaveBeenCalledWith(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
expect(getVideoStream).toHaveBeenCalledWith(
|
|
141
|
+
{
|
|
142
|
+
deviceId: undefined,
|
|
143
|
+
width: 1280,
|
|
144
|
+
height: 720,
|
|
145
|
+
},
|
|
146
|
+
expect.any(Tracer),
|
|
147
|
+
);
|
|
141
148
|
|
|
142
149
|
await manager.selectDirection('front');
|
|
143
150
|
|
|
144
|
-
expect(getVideoStream).toHaveBeenCalledWith(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
expect(getVideoStream).toHaveBeenCalledWith(
|
|
152
|
+
{
|
|
153
|
+
deviceId: undefined,
|
|
154
|
+
width: 1280,
|
|
155
|
+
height: 720,
|
|
156
|
+
facingMode: 'user',
|
|
157
|
+
},
|
|
158
|
+
expect.any(Tracer),
|
|
159
|
+
);
|
|
150
160
|
|
|
151
161
|
await manager.selectDirection('back');
|
|
152
162
|
|
|
153
|
-
expect(getVideoStream).toHaveBeenCalledWith(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
163
|
+
expect(getVideoStream).toHaveBeenCalledWith(
|
|
164
|
+
{
|
|
165
|
+
deviceId: undefined,
|
|
166
|
+
facingMode: 'environment',
|
|
167
|
+
width: 1280,
|
|
168
|
+
height: 720,
|
|
169
|
+
},
|
|
170
|
+
expect.any(Tracer),
|
|
171
|
+
);
|
|
159
172
|
});
|
|
160
173
|
|
|
161
174
|
it(`shouldn't set deviceId and facingMode at the same time`, async () => {
|
|
@@ -163,11 +176,14 @@ describe('CameraManager', () => {
|
|
|
163
176
|
|
|
164
177
|
await manager.flip();
|
|
165
178
|
|
|
166
|
-
expect(getVideoStream).toHaveBeenCalledWith(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
179
|
+
expect(getVideoStream).toHaveBeenCalledWith(
|
|
180
|
+
{
|
|
181
|
+
facingMode: 'environment',
|
|
182
|
+
width: 1280,
|
|
183
|
+
height: 720,
|
|
184
|
+
},
|
|
185
|
+
expect.any(Tracer),
|
|
186
|
+
);
|
|
171
187
|
|
|
172
188
|
const deviceId = mockVideoDevices[1].deviceId;
|
|
173
189
|
await manager.select(deviceId);
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
SoundStateChangeHandler,
|
|
25
25
|
} from '../../helpers/sound-detector';
|
|
26
26
|
import { PermissionsContext } from '../../permissions';
|
|
27
|
+
import { Tracer } from '../../stats';
|
|
27
28
|
|
|
28
29
|
vi.mock('../devices.ts', () => {
|
|
29
30
|
console.log('MOCKING devices API');
|
|
@@ -92,9 +93,10 @@ describe('MicrophoneManager', () => {
|
|
|
92
93
|
it('get stream', async () => {
|
|
93
94
|
await manager.enable();
|
|
94
95
|
|
|
95
|
-
expect(getAudioStream).toHaveBeenCalledWith(
|
|
96
|
-
deviceId: undefined,
|
|
97
|
-
|
|
96
|
+
expect(getAudioStream).toHaveBeenCalledWith(
|
|
97
|
+
{ deviceId: undefined },
|
|
98
|
+
expect.any(Tracer),
|
|
99
|
+
);
|
|
98
100
|
});
|
|
99
101
|
|
|
100
102
|
it('should get device id from stream', async () => {
|
|
@@ -7,6 +7,7 @@ import * as RxUtils from '../../store/rxUtils';
|
|
|
7
7
|
import { mockCall, mockDeviceIds$, mockScreenShareStream } from './mocks';
|
|
8
8
|
import { getScreenShareStream } from '../devices';
|
|
9
9
|
import { TrackType } from '../../gen/video/sfu/models/models';
|
|
10
|
+
import { Tracer } from '../../stats';
|
|
10
11
|
|
|
11
12
|
vi.mock('../devices.ts', () => {
|
|
12
13
|
console.log('MOCKING devices API');
|
|
@@ -50,7 +51,7 @@ describe('ScreenShareManager', () => {
|
|
|
50
51
|
});
|
|
51
52
|
|
|
52
53
|
it('select device', async () => {
|
|
53
|
-
await expect(manager.select(
|
|
54
|
+
await expect(manager.select()).rejects.toThrowError();
|
|
54
55
|
});
|
|
55
56
|
|
|
56
57
|
it('get stream', async () => {
|
|
@@ -62,6 +63,7 @@ describe('ScreenShareManager', () => {
|
|
|
62
63
|
expect.objectContaining({
|
|
63
64
|
deviceId: undefined,
|
|
64
65
|
}),
|
|
66
|
+
expect.any(Tracer),
|
|
65
67
|
);
|
|
66
68
|
});
|
|
67
69
|
|
|
@@ -75,6 +77,7 @@ describe('ScreenShareManager', () => {
|
|
|
75
77
|
deviceId: undefined,
|
|
76
78
|
audio: false,
|
|
77
79
|
}),
|
|
80
|
+
expect.any(Tracer),
|
|
78
81
|
);
|
|
79
82
|
});
|
|
80
83
|
|
|
@@ -106,6 +109,7 @@ describe('ScreenShareManager', () => {
|
|
|
106
109
|
height: 600,
|
|
107
110
|
},
|
|
108
111
|
}),
|
|
112
|
+
expect.any(Tracer),
|
|
109
113
|
);
|
|
110
114
|
});
|
|
111
115
|
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { Call } from '../../Call';
|
|
8
8
|
import { of, Subject } from 'rxjs';
|
|
9
9
|
import { BrowserPermission } from '../BrowserPermission';
|
|
10
|
+
import { Tracer } from '../../stats';
|
|
10
11
|
|
|
11
12
|
export const mockVideoDevices = [
|
|
12
13
|
{
|
|
@@ -93,13 +94,11 @@ export const mockCall = (): Partial<Call> => {
|
|
|
93
94
|
});
|
|
94
95
|
return {
|
|
95
96
|
state: callState,
|
|
96
|
-
publishVideoStream: vi.fn(),
|
|
97
|
-
publishAudioStream: vi.fn(),
|
|
98
|
-
publishScreenShareStream: vi.fn(),
|
|
99
97
|
publish: vi.fn(),
|
|
100
98
|
stopPublish: vi.fn(),
|
|
101
99
|
notifyNoiseCancellationStarting: vi.fn().mockResolvedValue(undefined),
|
|
102
100
|
notifyNoiseCancellationStopped: vi.fn().mockResolvedValue(undefined),
|
|
101
|
+
tracer: new Tracer('tests'),
|
|
103
102
|
};
|
|
104
103
|
};
|
|
105
104
|
|
package/src/devices/devices.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { getLogger } from '../logger';
|
|
|
12
12
|
import { BrowserPermission } from './BrowserPermission';
|
|
13
13
|
import { lazy } from '../helpers/lazy';
|
|
14
14
|
import { isFirefox } from '../helpers/browsers';
|
|
15
|
+
import { dumpStream, Tracer } from '../stats';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Returns an Observable that emits the list of available devices
|
|
@@ -158,15 +159,27 @@ export const getAudioOutputDevices = lazy(() => {
|
|
|
158
159
|
);
|
|
159
160
|
});
|
|
160
161
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
162
|
+
let getUserMediaExecId = 0;
|
|
163
|
+
const getStream = async (
|
|
164
|
+
constraints: MediaStreamConstraints,
|
|
165
|
+
tracer: Tracer | undefined,
|
|
166
|
+
) => {
|
|
167
|
+
const tag = `navigator.mediaDevices.getUserMedia.${getUserMediaExecId++}.`;
|
|
168
|
+
try {
|
|
169
|
+
tracer?.trace(tag, constraints);
|
|
170
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
171
|
+
tracer?.trace(`${tag}OnSuccess`, dumpStream(stream));
|
|
172
|
+
if (isFirefox()) {
|
|
173
|
+
// When enumerating devices, Firefox will hide device labels unless there's been
|
|
174
|
+
// an active user media stream on the page. So we force device list updates after
|
|
175
|
+
// every successful getUserMedia call.
|
|
176
|
+
navigator.mediaDevices.dispatchEvent(new Event('devicechange'));
|
|
177
|
+
}
|
|
178
|
+
return stream;
|
|
179
|
+
} catch (error) {
|
|
180
|
+
tracer?.trace(`${tag}OnFailure`, (error as Error).name);
|
|
181
|
+
throw error;
|
|
168
182
|
}
|
|
169
|
-
return stream;
|
|
170
183
|
};
|
|
171
184
|
|
|
172
185
|
function isNotFoundOrOverconstrainedError(error: unknown) {
|
|
@@ -195,12 +208,13 @@ function isNotFoundOrOverconstrainedError(error: unknown) {
|
|
|
195
208
|
* Returns an audio media stream that fulfills the given constraints.
|
|
196
209
|
* If no constraints are provided, it uses the browser's default ones.
|
|
197
210
|
*
|
|
198
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
199
211
|
* @param trackConstraints the constraints to use when requesting the stream.
|
|
200
|
-
* @
|
|
212
|
+
* @param tracer the tracer to use for tracing the stream creation.
|
|
213
|
+
* @returns a new `MediaStream` fulfilling the given constraints.
|
|
201
214
|
*/
|
|
202
215
|
export const getAudioStream = async (
|
|
203
216
|
trackConstraints?: MediaTrackConstraints,
|
|
217
|
+
tracer?: Tracer,
|
|
204
218
|
): Promise<MediaStream> => {
|
|
205
219
|
const constraints: MediaStreamConstraints = {
|
|
206
220
|
audio: {
|
|
@@ -214,7 +228,7 @@ export const getAudioStream = async (
|
|
|
214
228
|
throwOnNotAllowed: true,
|
|
215
229
|
forcePrompt: true,
|
|
216
230
|
});
|
|
217
|
-
return await getStream(constraints);
|
|
231
|
+
return await getStream(constraints, tracer);
|
|
218
232
|
} catch (error) {
|
|
219
233
|
if (isNotFoundOrOverconstrainedError(error) && trackConstraints?.deviceId) {
|
|
220
234
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -239,12 +253,13 @@ export const getAudioStream = async (
|
|
|
239
253
|
* Returns a video media stream that fulfills the given constraints.
|
|
240
254
|
* If no constraints are provided, it uses the browser's default ones.
|
|
241
255
|
*
|
|
242
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
243
256
|
* @param trackConstraints the constraints to use when requesting the stream.
|
|
257
|
+
* @param tracer the tracer to use for tracing the stream creation.
|
|
244
258
|
* @returns a new `MediaStream` fulfilling the given constraints.
|
|
245
259
|
*/
|
|
246
260
|
export const getVideoStream = async (
|
|
247
261
|
trackConstraints?: MediaTrackConstraints,
|
|
262
|
+
tracer?: Tracer,
|
|
248
263
|
): Promise<MediaStream> => {
|
|
249
264
|
const constraints: MediaStreamConstraints = {
|
|
250
265
|
video: {
|
|
@@ -257,7 +272,7 @@ export const getVideoStream = async (
|
|
|
257
272
|
throwOnNotAllowed: true,
|
|
258
273
|
forcePrompt: true,
|
|
259
274
|
});
|
|
260
|
-
return await getStream(constraints);
|
|
275
|
+
return await getStream(constraints, tracer);
|
|
261
276
|
} catch (error) {
|
|
262
277
|
if (isNotFoundOrOverconstrainedError(error) && trackConstraints?.deviceId) {
|
|
263
278
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -278,21 +293,25 @@ export const getVideoStream = async (
|
|
|
278
293
|
}
|
|
279
294
|
};
|
|
280
295
|
|
|
296
|
+
let getDisplayMediaExecId = 0;
|
|
297
|
+
|
|
281
298
|
/**
|
|
282
299
|
* Prompts the user for a permission to share a screen.
|
|
283
300
|
* If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
|
|
284
301
|
*
|
|
285
302
|
* The callers of this API are responsible to handle the possible errors.
|
|
286
303
|
*
|
|
287
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
288
|
-
*
|
|
289
304
|
* @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
|
|
305
|
+
* @param tracer the tracer to use for tracing the stream creation.
|
|
290
306
|
*/
|
|
291
307
|
export const getScreenShareStream = async (
|
|
292
308
|
options?: DisplayMediaStreamOptions,
|
|
309
|
+
tracer?: Tracer | undefined,
|
|
293
310
|
) => {
|
|
311
|
+
const tag = `navigator.mediaDevices.getDisplayMedia.${getDisplayMediaExecId++}.`;
|
|
294
312
|
try {
|
|
295
|
-
|
|
313
|
+
tracer?.trace(tag, options);
|
|
314
|
+
const stream = await navigator.mediaDevices.getDisplayMedia({
|
|
296
315
|
video: true,
|
|
297
316
|
audio: {
|
|
298
317
|
channelCount: {
|
|
@@ -306,7 +325,10 @@ export const getScreenShareStream = async (
|
|
|
306
325
|
systemAudio: 'include',
|
|
307
326
|
...options,
|
|
308
327
|
});
|
|
328
|
+
tracer?.trace(`${tag}OnSuccess`, dumpStream(stream));
|
|
329
|
+
return stream;
|
|
309
330
|
} catch (e) {
|
|
331
|
+
tracer?.trace(`${tag}OnFailure`, (e as Error).name);
|
|
310
332
|
getLogger(['devices'])('error', 'Failed to get screen share stream', e);
|
|
311
333
|
throw e;
|
|
312
334
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
CallAcceptedEvent,
|
|
11
11
|
CallEndedEvent,
|
|
12
12
|
CallResponse,
|
|
13
|
+
OwnCapability,
|
|
13
14
|
RejectCallResponse,
|
|
14
15
|
} from '../../gen/coordinator';
|
|
15
16
|
import { Call } from '../../Call';
|
|
@@ -295,6 +296,28 @@ describe('Call ringing events', () => {
|
|
|
295
296
|
|
|
296
297
|
expect(call.leave).not.toHaveBeenCalled();
|
|
297
298
|
});
|
|
299
|
+
|
|
300
|
+
it('will stay in backstage if live ended and has permission', async () => {
|
|
301
|
+
const call = fakeCall();
|
|
302
|
+
call.state.setBackstage(false);
|
|
303
|
+
call.permissionsContext.setPermissions([OwnCapability.JOIN_BACKSTAGE]);
|
|
304
|
+
vi.spyOn(call, 'leave').mockImplementation(async () => {
|
|
305
|
+
console.log(`TEST: leave() called`);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
watchSfuCallEnded(call);
|
|
309
|
+
const event: SfuEvent = {
|
|
310
|
+
eventPayload: {
|
|
311
|
+
oneofKind: 'callEnded',
|
|
312
|
+
callEnded: { reason: CallEndedReason.LIVE_ENDED },
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
// @ts-expect-error type issue
|
|
316
|
+
call['dispatcher'].dispatch(event);
|
|
317
|
+
|
|
318
|
+
expect(call.leave).not.toHaveBeenCalled();
|
|
319
|
+
expect(call.state.backstage).toBe(true);
|
|
320
|
+
});
|
|
298
321
|
});
|
|
299
322
|
|
|
300
323
|
describe('call.leave', () => {
|
package/src/events/call.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { CallingState } from '../store';
|
|
2
2
|
import { Call } from '../Call';
|
|
3
|
-
import
|
|
3
|
+
import {
|
|
4
|
+
CallAcceptedEvent,
|
|
5
|
+
CallRejectedEvent,
|
|
6
|
+
OwnCapability,
|
|
7
|
+
} from '../gen/coordinator';
|
|
4
8
|
import { CallEnded } from '../gen/video/sfu/event/events';
|
|
5
9
|
import { CallEndedReason } from '../gen/video/sfu/models/models';
|
|
6
10
|
|
|
@@ -99,6 +103,13 @@ export const watchSfuCallEnded = (call: Call) => {
|
|
|
99
103
|
return call.on('callEnded', async (e: CallEnded) => {
|
|
100
104
|
if (call.state.callingState === CallingState.LEFT) return;
|
|
101
105
|
try {
|
|
106
|
+
if (e.reason === CallEndedReason.LIVE_ENDED) {
|
|
107
|
+
call.state.setBackstage(true);
|
|
108
|
+
|
|
109
|
+
// don't leave the call if the user has permission to join backstage
|
|
110
|
+
const { hasPermission } = call.permissionsContext;
|
|
111
|
+
if (hasPermission(OwnCapability.JOIN_BACKSTAGE)) return;
|
|
112
|
+
}
|
|
102
113
|
// `call.ended` event arrived after the call is already left
|
|
103
114
|
// and all event handlers are detached. We need to manually
|
|
104
115
|
// update the call state to reflect the call has ended.
|
|
@@ -626,6 +626,49 @@ export interface AppleState {
|
|
|
626
626
|
*/
|
|
627
627
|
isLowPowerModeEnabled: boolean;
|
|
628
628
|
}
|
|
629
|
+
/**
|
|
630
|
+
* PerformanceStats represents the encoding/decoding statistics for a track.
|
|
631
|
+
*
|
|
632
|
+
* @generated from protobuf message stream.video.sfu.models.PerformanceStats
|
|
633
|
+
*/
|
|
634
|
+
export interface PerformanceStats {
|
|
635
|
+
/**
|
|
636
|
+
* the type of the track (e.g., video, audio, screen share)
|
|
637
|
+
*
|
|
638
|
+
* @generated from protobuf field: stream.video.sfu.models.TrackType track_type = 1;
|
|
639
|
+
*/
|
|
640
|
+
trackType: TrackType;
|
|
641
|
+
/**
|
|
642
|
+
* the codec used for the track
|
|
643
|
+
*
|
|
644
|
+
* @generated from protobuf field: stream.video.sfu.models.Codec codec = 2;
|
|
645
|
+
*/
|
|
646
|
+
codec?: Codec;
|
|
647
|
+
/**
|
|
648
|
+
* the average encode/decode time in ms
|
|
649
|
+
*
|
|
650
|
+
* @generated from protobuf field: float avg_frame_time_ms = 3;
|
|
651
|
+
*/
|
|
652
|
+
avgFrameTimeMs: number;
|
|
653
|
+
/**
|
|
654
|
+
* the average fps for the track
|
|
655
|
+
*
|
|
656
|
+
* @generated from protobuf field: float avg_fps = 4;
|
|
657
|
+
*/
|
|
658
|
+
avgFps: number;
|
|
659
|
+
/**
|
|
660
|
+
* the track dimensions
|
|
661
|
+
*
|
|
662
|
+
* @generated from protobuf field: stream.video.sfu.models.VideoDimension video_dimension = 5;
|
|
663
|
+
*/
|
|
664
|
+
videoDimension?: VideoDimension;
|
|
665
|
+
/**
|
|
666
|
+
* the target bitrate for the track, only for published tracks
|
|
667
|
+
*
|
|
668
|
+
* @generated from protobuf field: int32 target_bitrate = 6;
|
|
669
|
+
*/
|
|
670
|
+
targetBitrate: number;
|
|
671
|
+
}
|
|
629
672
|
/**
|
|
630
673
|
* @generated from protobuf enum stream.video.sfu.models.PeerType
|
|
631
674
|
*/
|
|
@@ -1636,3 +1679,44 @@ class AppleState$Type extends MessageType<AppleState> {
|
|
|
1636
1679
|
* @generated MessageType for protobuf message stream.video.sfu.models.AppleState
|
|
1637
1680
|
*/
|
|
1638
1681
|
export const AppleState = new AppleState$Type();
|
|
1682
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1683
|
+
class PerformanceStats$Type extends MessageType<PerformanceStats> {
|
|
1684
|
+
constructor() {
|
|
1685
|
+
super('stream.video.sfu.models.PerformanceStats', [
|
|
1686
|
+
{
|
|
1687
|
+
no: 1,
|
|
1688
|
+
name: 'track_type',
|
|
1689
|
+
kind: 'enum',
|
|
1690
|
+
T: () => [
|
|
1691
|
+
'stream.video.sfu.models.TrackType',
|
|
1692
|
+
TrackType,
|
|
1693
|
+
'TRACK_TYPE_',
|
|
1694
|
+
],
|
|
1695
|
+
},
|
|
1696
|
+
{ no: 2, name: 'codec', kind: 'message', T: () => Codec },
|
|
1697
|
+
{
|
|
1698
|
+
no: 3,
|
|
1699
|
+
name: 'avg_frame_time_ms',
|
|
1700
|
+
kind: 'scalar',
|
|
1701
|
+
T: 2 /*ScalarType.FLOAT*/,
|
|
1702
|
+
},
|
|
1703
|
+
{ no: 4, name: 'avg_fps', kind: 'scalar', T: 2 /*ScalarType.FLOAT*/ },
|
|
1704
|
+
{
|
|
1705
|
+
no: 5,
|
|
1706
|
+
name: 'video_dimension',
|
|
1707
|
+
kind: 'message',
|
|
1708
|
+
T: () => VideoDimension,
|
|
1709
|
+
},
|
|
1710
|
+
{
|
|
1711
|
+
no: 6,
|
|
1712
|
+
name: 'target_bitrate',
|
|
1713
|
+
kind: 'scalar',
|
|
1714
|
+
T: 5 /*ScalarType.INT32*/,
|
|
1715
|
+
},
|
|
1716
|
+
]);
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
/**
|
|
1720
|
+
* @generated MessageType for protobuf message stream.video.sfu.models.PerformanceStats
|
|
1721
|
+
*/
|
|
1722
|
+
export const PerformanceStats = new PerformanceStats$Type();
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
ICETrickle,
|
|
9
9
|
InputDevices,
|
|
10
10
|
PeerType,
|
|
11
|
+
PerformanceStats,
|
|
11
12
|
RTMPIngress,
|
|
12
13
|
TrackInfo,
|
|
13
14
|
TrackType,
|
|
@@ -158,13 +159,39 @@ export interface SendStatsRequest {
|
|
|
158
159
|
*/
|
|
159
160
|
rtmp?: RTMPIngress;
|
|
160
161
|
/**
|
|
161
|
-
* @
|
|
162
|
+
* @deprecated
|
|
163
|
+
* @generated from protobuf field: string subscriber_rtc_stats = 13 [deprecated = true];
|
|
162
164
|
*/
|
|
163
165
|
subscriberRtcStats: string;
|
|
164
166
|
/**
|
|
165
|
-
* @
|
|
167
|
+
* @deprecated
|
|
168
|
+
* @generated from protobuf field: string publisher_rtc_stats = 14 [deprecated = true];
|
|
166
169
|
*/
|
|
167
170
|
publisherRtcStats: string;
|
|
171
|
+
/**
|
|
172
|
+
* @generated from protobuf field: string rtc_stats = 15;
|
|
173
|
+
*/
|
|
174
|
+
rtcStats: string;
|
|
175
|
+
/**
|
|
176
|
+
* Encode stats for the publisher
|
|
177
|
+
*
|
|
178
|
+
* @generated from protobuf field: repeated stream.video.sfu.models.PerformanceStats encode_stats = 16;
|
|
179
|
+
*/
|
|
180
|
+
encodeStats: PerformanceStats[];
|
|
181
|
+
/**
|
|
182
|
+
* Decode stats for the subscriber
|
|
183
|
+
*
|
|
184
|
+
* @generated from protobuf field: repeated stream.video.sfu.models.PerformanceStats decode_stats = 17;
|
|
185
|
+
*/
|
|
186
|
+
decodeStats: PerformanceStats[];
|
|
187
|
+
/**
|
|
188
|
+
* user_session id can change during reconnects, this helps us to
|
|
189
|
+
* identify the user across reconnects and should remain consistent until the user explicitly
|
|
190
|
+
* disconnects, is kicked or the call is ended.
|
|
191
|
+
*
|
|
192
|
+
* @generated from protobuf field: string unified_session_id = 18;
|
|
193
|
+
*/
|
|
194
|
+
unifiedSessionId: string;
|
|
168
195
|
}
|
|
169
196
|
/**
|
|
170
197
|
* @generated from protobuf message stream.video.sfu.signal.SendStatsResponse
|
|
@@ -534,6 +561,27 @@ class SendStatsRequest$Type extends MessageType<SendStatsRequest> {
|
|
|
534
561
|
kind: 'scalar',
|
|
535
562
|
T: 9 /*ScalarType.STRING*/,
|
|
536
563
|
},
|
|
564
|
+
{ no: 15, name: 'rtc_stats', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
|
|
565
|
+
{
|
|
566
|
+
no: 16,
|
|
567
|
+
name: 'encode_stats',
|
|
568
|
+
kind: 'message',
|
|
569
|
+
repeat: 1 /*RepeatType.PACKED*/,
|
|
570
|
+
T: () => PerformanceStats,
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
no: 17,
|
|
574
|
+
name: 'decode_stats',
|
|
575
|
+
kind: 'message',
|
|
576
|
+
repeat: 1 /*RepeatType.PACKED*/,
|
|
577
|
+
T: () => PerformanceStats,
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
no: 18,
|
|
581
|
+
name: 'unified_session_id',
|
|
582
|
+
kind: 'scalar',
|
|
583
|
+
T: 9 /*ScalarType.STRING*/,
|
|
584
|
+
},
|
|
537
585
|
]);
|
|
538
586
|
}
|
|
539
587
|
}
|
|
@@ -28,7 +28,6 @@ import type { CallState } from '../store';
|
|
|
28
28
|
import type { StreamSfuClient } from '../StreamSfuClient';
|
|
29
29
|
import { SpeakerManager } from '../devices';
|
|
30
30
|
import { getCurrentValue, setCurrentValue } from '../store/rxUtils';
|
|
31
|
-
import { tracer as mediaStatsTracer } from '../stats/rtc/mediaDevices';
|
|
32
31
|
|
|
33
32
|
const DEFAULT_VIEWPORT_VISIBILITY_STATE: Record<
|
|
34
33
|
VideoTrackType,
|
|
@@ -536,10 +535,6 @@ export class DynascaleManager {
|
|
|
536
535
|
const { selectedDevice } = this.speaker.state;
|
|
537
536
|
if (selectedDevice && 'setSinkId' in audioElement) {
|
|
538
537
|
audioElement.setSinkId(selectedDevice);
|
|
539
|
-
mediaStatsTracer.trace(
|
|
540
|
-
'navigator.mediaDevices.setSinkId',
|
|
541
|
-
selectedDevice,
|
|
542
|
-
);
|
|
543
538
|
}
|
|
544
539
|
}
|
|
545
540
|
});
|
|
@@ -550,10 +545,6 @@ export class DynascaleManager {
|
|
|
550
545
|
: this.speaker.state.selectedDevice$.subscribe((deviceId) => {
|
|
551
546
|
if (deviceId) {
|
|
552
547
|
audioElement.setSinkId(deviceId);
|
|
553
|
-
mediaStatsTracer.trace(
|
|
554
|
-
'navigator.mediaDevices.setSinkId',
|
|
555
|
-
deviceId,
|
|
556
|
-
);
|
|
557
548
|
}
|
|
558
549
|
});
|
|
559
550
|
|
package/src/rpc/createClient.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from '@protobuf-ts/twirp-transport';
|
|
12
12
|
import { SignalServerClient } from '../gen/video/sfu/signal_rpc/signal.client';
|
|
13
13
|
import { Logger, LogLevel } from '../coordinator/connection/types';
|
|
14
|
-
import type { Trace } from '../stats
|
|
14
|
+
import type { Trace } from '../stats';
|
|
15
15
|
|
|
16
16
|
const defaultOptions: TwirpOptions = {
|
|
17
17
|
baseUrl: '',
|