@stream-io/video-client 1.54.0 → 1.55.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/index.browser.es.js +9641 -8767
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +9638 -8764
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +9639 -8765
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/src/Call.d.ts +13 -1
  9. package/dist/src/StreamSfuClient.d.ts +11 -3
  10. package/dist/src/coordinator/connection/connection.d.ts +1 -1
  11. package/dist/src/gen/google/protobuf/struct.d.ts +3 -1
  12. package/dist/src/gen/google/protobuf/timestamp.d.ts +3 -1
  13. package/dist/src/gen/video/sfu/event/events.d.ts +22 -1
  14. package/dist/src/gen/video/sfu/models/models.d.ts +4 -0
  15. package/dist/src/gen/video/sfu/signal_rpc/signal.client.d.ts +23 -2
  16. package/dist/src/reporting/ClientEventReporter.d.ts +1 -0
  17. package/dist/src/rtc/BasePeerConnection.d.ts +2 -12
  18. package/dist/src/rtc/IceTrickleBuffer.d.ts +41 -3
  19. package/dist/src/rtc/Publisher.d.ts +5 -2
  20. package/dist/src/rtc/Subscriber.d.ts +8 -0
  21. package/dist/src/rtc/helpers/iceCandiates.d.ts +12 -0
  22. package/dist/src/rtc/types.d.ts +2 -0
  23. package/dist/src/stats/SfuStatsReporter.d.ts +32 -1
  24. package/dist/src/stats/rtc/StatsTracer.d.ts +38 -8
  25. package/dist/src/stats/rtc/Tracer.d.ts +9 -2
  26. package/dist/src/stats/rtc/types.d.ts +10 -4
  27. package/package.json +5 -3
  28. package/src/Call.ts +83 -35
  29. package/src/StreamSfuClient.ts +36 -21
  30. package/src/__tests__/StreamSfuClient.test.ts +159 -1
  31. package/src/__tests__/StreamVideoClient.api.test.ts +123 -97
  32. package/src/coordinator/connection/__tests__/connection.test.ts +22 -0
  33. package/src/coordinator/connection/connection.ts +8 -5
  34. package/src/gen/google/protobuf/struct.ts +7 -12
  35. package/src/gen/google/protobuf/timestamp.ts +6 -7
  36. package/src/gen/video/sfu/event/events.ts +22 -25
  37. package/src/gen/video/sfu/models/models.ts +10 -1
  38. package/src/gen/video/sfu/signal_rpc/signal.client.ts +24 -29
  39. package/src/helpers/MediaPlaybackWatchdog.ts +1 -0
  40. package/src/helpers/__tests__/browsers.test.ts +12 -12
  41. package/src/helpers/browsers.ts +5 -5
  42. package/src/reporting/ClientEventReporter.ts +17 -12
  43. package/src/reporting/__tests__/ClientEventReporter.test.ts +52 -0
  44. package/src/rtc/BasePeerConnection.ts +15 -34
  45. package/src/rtc/IceTrickleBuffer.ts +105 -12
  46. package/src/rtc/Publisher.ts +23 -19
  47. package/src/rtc/Subscriber.ts +97 -36
  48. package/src/rtc/__tests__/Call.reconnect.test.ts +45 -45
  49. package/src/rtc/__tests__/IceTrickleBuffer.test.ts +127 -0
  50. package/src/rtc/__tests__/Publisher.test.ts +2 -31
  51. package/src/rtc/__tests__/Subscriber.test.ts +271 -20
  52. package/src/rtc/helpers/__tests__/iceCandiates.test.ts +88 -0
  53. package/src/rtc/helpers/degradationPreference.ts +1 -0
  54. package/src/rtc/helpers/iceCandiates.ts +35 -0
  55. package/src/rtc/helpers/sdp.ts +3 -2
  56. package/src/rtc/helpers/tracks.ts +2 -0
  57. package/src/rtc/types.ts +2 -0
  58. package/src/stats/SfuStatsReporter.ts +149 -49
  59. package/src/stats/__tests__/SfuStatsReporter.test.ts +235 -0
  60. package/src/stats/rtc/StatsTracer.ts +90 -32
  61. package/src/stats/rtc/Tracer.ts +23 -2
  62. package/src/stats/rtc/__tests__/StatsTracer.test.ts +213 -6
  63. package/src/stats/rtc/__tests__/Tracer.test.ts +34 -0
  64. package/src/stats/rtc/types.ts +11 -4
@@ -1,94 +1,122 @@
1
- import { afterAll, beforeAll, describe, expect, it } from 'vitest';
1
+ import {
2
+ afterEach,
3
+ beforeEach,
4
+ describe,
5
+ expect,
6
+ it,
7
+ type Mock,
8
+ vi,
9
+ } from 'vitest';
2
10
  import { StreamVideoClient } from '../StreamVideoClient';
3
- import 'dotenv/config';
11
+ import { Call } from '../Call';
12
+ import { CallCreatedPayload } from './data';
4
13
  import { generateUUIDv4 } from '../coordinator/connection/utils';
5
- import { StreamClient } from '@stream-io/node-sdk';
6
- import { CreateDeviceRequest } from '../gen/coordinator';
14
+ import type { StreamClient } from '../coordinator/connection/client';
15
+ import type {
16
+ CreateDeviceRequest,
17
+ GetEdgesResponse,
18
+ ListDevicesResponse,
19
+ QueryCallsResponse,
20
+ QueryCallStatsResponse,
21
+ } from '../gen/coordinator';
7
22
 
8
- const apiKey = process.env.STREAM_API_KEY!;
9
- const secret = process.env.STREAM_SECRET!;
10
-
11
- const serverClient = new StreamClient(apiKey, secret);
23
+ const apiKey = 'mock-api-key';
12
24
 
13
25
  describe('StreamVideoClient - coordinator API', () => {
14
26
  let client: StreamVideoClient;
27
+ // the client only talks to the backend through streamClient.post/get/delete,
28
+ // so we spy on those and assert against them instead of a live backend.
29
+ let post: Mock<StreamClient['post']>;
30
+ let get: Mock<StreamClient['get']>;
31
+ let del: Mock<StreamClient['delete']>;
32
+
33
+ beforeEach(() => {
34
+ client = new StreamVideoClient(apiKey, { browser: true });
35
+ post = vi.spyOn(client.streamClient, 'post');
36
+ get = vi.spyOn(client.streamClient, 'get');
37
+ del = vi.spyOn(client.streamClient, 'delete');
38
+ });
15
39
 
16
- beforeAll(() => {
17
- const user = { id: 'sara' };
18
- client = new StreamVideoClient(apiKey, {
19
- // tests run in node, so we have to fake being in browser env
20
- browser: true,
21
- timeout: 15000,
22
- });
23
- client.connectUser(
24
- user,
25
- serverClient.generateUserToken({ user_id: user.id }),
26
- );
40
+ afterEach(() => {
41
+ vi.restoreAllMocks();
27
42
  });
28
43
 
29
- it('query calls', { retry: 3, timeout: 20000 }, async () => {
30
- let response = await client.queryCalls();
44
+ it('query calls', async () => {
45
+ const response: QueryCallsResponse = {
46
+ duration: '1ms',
47
+ next: 'next-page-token',
48
+ calls: [
49
+ {
50
+ call: CallCreatedPayload.call,
51
+ members: CallCreatedPayload.members,
52
+ own_capabilities: [],
53
+ },
54
+ ],
55
+ };
56
+ post.mockResolvedValue(response);
31
57
 
32
- let calls = response.calls;
33
- expect(calls.length).toBeGreaterThanOrEqual(1);
58
+ await client.queryCalls();
59
+ expect(post).toHaveBeenCalledWith('/calls', {});
34
60
 
35
61
  const queryCallsReq = {
36
62
  sort: [{ field: 'starts_at', direction: -1 }],
37
63
  limit: 2,
38
64
  };
39
- response = await client.queryCalls(queryCallsReq);
40
-
41
- calls = response.calls;
42
- expect(calls.length).toBe(2);
43
-
44
- response = await client.queryCalls({
45
- ...queryCallsReq,
46
- next: response.next,
47
- });
48
-
49
- expect(response.calls.length).toBeLessThanOrEqual(2);
50
-
51
- response = await client.queryCalls({
52
- filter_conditions: { backstage: { $eq: false } },
53
- });
54
-
55
- expect(response.calls.length).toBeGreaterThanOrEqual(1);
65
+ const result = await client.queryCalls(queryCallsReq);
66
+ expect(post).toHaveBeenCalledWith('/calls', queryCallsReq);
67
+
68
+ // each response entry is wrapped into a Call instance
69
+ expect(result.next).toBe('next-page-token');
70
+ expect(result.calls).toHaveLength(1);
71
+ const [call] = result.calls;
72
+ expect(call).toBeInstanceOf(Call);
73
+ expect(call.cid).toBe(CallCreatedPayload.call.cid);
56
74
  });
57
75
 
58
76
  it('query calls - ongoing', async () => {
59
- const response = await client.queryCalls({
60
- filter_conditions: { ongoing: { $eq: true } },
61
- });
77
+ post.mockResolvedValue({ duration: '1ms', calls: [] });
78
+
79
+ const queryCallsReq = { filter_conditions: { ongoing: { $eq: true } } };
80
+ await client.queryCalls(queryCallsReq);
62
81
 
63
- // Dummy test
64
- expect(response.calls).toBeDefined();
82
+ expect(post).toHaveBeenCalledWith('/calls', queryCallsReq);
65
83
  });
66
84
 
67
85
  it('query calls - upcoming', async () => {
86
+ post.mockResolvedValue({ duration: '1ms', calls: [] });
87
+
68
88
  const mins30 = 1000 * 60 * 60 * 30;
69
89
  const inNext30mins = new Date(Date.now() + mins30);
70
- const response = await client.queryCalls({
71
- filter_conditions: {
72
- starts_at: { $gt: inNext30mins.toISOString() },
73
- },
74
- });
90
+ const queryCallsReq = {
91
+ filter_conditions: { starts_at: { $gt: inNext30mins.toISOString() } },
92
+ };
93
+ await client.queryCalls(queryCallsReq);
75
94
 
76
- // Dummy test
77
- expect(response.calls).toBeDefined();
95
+ expect(post).toHaveBeenCalledWith('/calls', queryCallsReq);
78
96
  });
79
97
 
80
98
  it('query call stats', async () => {
81
- const response = await client.queryCallStats({
99
+ const response: QueryCallStatsResponse = { duration: '1ms', reports: [] };
100
+ post.mockResolvedValue(response);
101
+
102
+ const result = await client.queryCallStats({
82
103
  filter_conditions: { call_cid: 'default:test' },
83
104
  });
84
105
 
85
- expect(response.reports).toBeDefined();
106
+ expect(post).toHaveBeenCalledWith('/call/stats', {
107
+ filter_conditions: { call_cid: 'default:test' },
108
+ });
109
+ expect(result).toBe(response);
86
110
  });
87
111
 
88
112
  it('edges', async () => {
89
- const response = await client.edges();
113
+ const response: GetEdgesResponse = { duration: '1ms', edges: [] };
114
+ get.mockResolvedValue(response);
115
+
116
+ const result = await client.edges();
90
117
 
91
- expect(response.edges).toBeDefined();
118
+ expect(get).toHaveBeenCalledWith('/edges');
119
+ expect(result).toBe(response);
92
120
  });
93
121
 
94
122
  describe('devices', () => {
@@ -99,57 +127,55 @@ describe('StreamVideoClient - coordinator API', () => {
99
127
  };
100
128
 
101
129
  it('add device', async () => {
102
- expect(
103
- async () =>
104
- await client.addDevice(
105
- device.id,
106
- device.push_provider,
107
- device.push_provider_name,
108
- ),
109
- ).not.toThrowError();
130
+ post.mockResolvedValue(undefined);
131
+
132
+ await client.addDevice(
133
+ device.id,
134
+ device.push_provider,
135
+ device.push_provider_name,
136
+ );
137
+
138
+ expect(post).toHaveBeenCalledWith('/devices', {
139
+ id: device.id,
140
+ push_provider: device.push_provider,
141
+ voip_token: undefined,
142
+ push_provider_name: device.push_provider_name,
143
+ });
110
144
  });
111
145
 
112
146
  it('add voip device', async () => {
113
- expect(
114
- async () =>
115
- await client.addVoipDevice(
116
- device.id + 'voip',
117
- device.push_provider,
118
- device.push_provider_name!,
119
- ),
120
- ).not.toThrowError();
147
+ post.mockResolvedValue(undefined);
148
+
149
+ await client.addVoipDevice(
150
+ device.id + 'voip',
151
+ device.push_provider,
152
+ device.push_provider_name!,
153
+ );
154
+
155
+ expect(post).toHaveBeenCalledWith('/devices', {
156
+ id: device.id + 'voip',
157
+ push_provider: device.push_provider,
158
+ voip_token: true,
159
+ push_provider_name: device.push_provider_name,
160
+ });
121
161
  });
122
162
 
123
- it('get devices', { retry: 3, timeout: 15000 }, async () => {
124
- // Wait a little bit, because if we query devices too soon backend will return 404
125
- await new Promise<void>((resolve) => {
126
- setTimeout(resolve, 5000);
127
- });
163
+ it('get devices', async () => {
164
+ const response: ListDevicesResponse = { duration: '1ms', devices: [] };
165
+ get.mockResolvedValue(response);
128
166
 
129
- const response = await client.getDevices();
167
+ const result = await client.getDevices();
130
168
 
131
- expect(response.devices.find((d) => d.id === device.id)).toBeDefined();
132
- expect(
133
- response.devices.find((d) => d.id === device.id + 'voip'),
134
- ).toBeDefined();
169
+ expect(get).toHaveBeenCalledWith('/devices', {});
170
+ expect(result).toBe(response);
135
171
  });
136
172
 
137
- it('remove device', { retry: 3, timeout: 15000 }, async () => {
138
- // Wait a little bit, because if we query devices too soon backend will return 404
139
- await new Promise<void>((resolve) => {
140
- setTimeout(resolve, 5000);
141
- });
173
+ it('remove device', async () => {
174
+ del.mockResolvedValue(undefined);
142
175
 
143
- expect(
144
- async () => await client.removeDevice(device.id),
145
- ).not.toThrowError();
146
- expect(
147
- async () => await client.removeDevice(device.id + 'void'),
148
- ).not.toThrowError();
149
- });
150
- });
176
+ await client.removeDevice(device.id);
151
177
 
152
- afterAll(() => {
153
- client.disconnectUser();
178
+ expect(del).toHaveBeenCalledWith('/devices', { id: device.id });
179
+ });
154
180
  });
155
181
  });
@@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
2
  import { StreamClient } from '../client';
3
3
  import { StableWSConnection } from '../connection';
4
4
  import type { WSConnectionError } from '../types';
5
+ import { getTimers } from '../../../timers';
5
6
 
6
7
  class StuckWebSocket {
7
8
  static CONNECTING = 0;
@@ -108,6 +109,27 @@ const buildClient = () => {
108
109
  return client;
109
110
  };
110
111
 
112
+ describe('StableWSConnection connection-check timer source', () => {
113
+ afterEach(() => {
114
+ vi.restoreAllMocks();
115
+ vi.useRealTimers();
116
+ });
117
+
118
+ it('arms the connection-check watchdog on the worker timer, not the main-thread setTimeout', () => {
119
+ const client = buildClient();
120
+ const wsConnection = new StableWSConnection(client);
121
+ const workerSetTimeout = vi
122
+ .spyOn(getTimers(), 'setTimeout')
123
+ .mockReturnValue(1 as unknown as number);
124
+ const mainSetTimeout = vi.spyOn(globalThis, 'setTimeout');
125
+
126
+ wsConnection.scheduleConnectionCheck();
127
+
128
+ expect(workerSetTimeout).toHaveBeenCalledTimes(1);
129
+ expect(mainSetTimeout).not.toHaveBeenCalled();
130
+ });
131
+ });
132
+
111
133
  describe('StableWSConnection - silent handshake hang', () => {
112
134
  beforeEach(() => {
113
135
  StuckWebSocket.instances = [];
@@ -72,7 +72,7 @@ export class StableWSConnection {
72
72
  pingInterval = 25 * 1000;
73
73
  healthCheckTimeoutRef?: number;
74
74
  connectionCheckTimeout = this.pingInterval + 10 * 1000;
75
- connectionCheckTimeoutRef?: NodeJS.Timeout;
75
+ connectionCheckTimeoutRef?: number;
76
76
  /** Store the last event time for health checks */
77
77
  lastEvent: Date | null = null;
78
78
 
@@ -174,6 +174,7 @@ export class StableWSConnection {
174
174
  await sleep(interval);
175
175
  }
176
176
  }
177
+ return undefined;
177
178
  })(),
178
179
  (async () => {
179
180
  await sleep(timeout);
@@ -221,7 +222,7 @@ export class StableWSConnection {
221
222
  getTimers().clearInterval(this.healthCheckTimeoutRef);
222
223
  }
223
224
  if (this.connectionCheckTimeoutRef) {
224
- clearInterval(this.connectionCheckTimeoutRef);
225
+ getTimers().clearTimeout(this.connectionCheckTimeoutRef);
225
226
  }
226
227
 
227
228
  removeConnectionEventListeners(this.onlineStatusChanged);
@@ -372,6 +373,7 @@ export class StableWSConnection {
372
373
  this.client.resolveConnectionId?.(this.connectionID);
373
374
  return response;
374
375
  }
376
+ return undefined;
375
377
  } catch (caught) {
376
378
  const err = caught as WSConnectionError;
377
379
  this.isConnecting = false;
@@ -579,7 +581,7 @@ export class StableWSConnection {
579
581
  code === KnownCodes.TOKEN_EXPIRED &&
580
582
  !this.client.tokenManager.isStatic()
581
583
  ) {
582
- clearTimeout(this.connectionCheckTimeoutRef);
584
+ getTimers().clearTimeout(this.connectionCheckTimeoutRef);
583
585
  this._log(
584
586
  'connect() - WS failure due to expired token, so going to try to reload token and reconnect',
585
587
  );
@@ -769,8 +771,9 @@ export class StableWSConnection {
769
771
  * to be reconnected.
770
772
  */
771
773
  scheduleConnectionCheck = () => {
772
- clearTimeout(this.connectionCheckTimeoutRef);
773
- this.connectionCheckTimeoutRef = setTimeout(() => {
774
+ const timers = getTimers();
775
+ timers.clearTimeout(this.connectionCheckTimeoutRef);
776
+ this.connectionCheckTimeoutRef = timers.setTimeout(() => {
774
777
  const now = new Date();
775
778
  if (
776
779
  this.lastEvent &&
@@ -1,10 +1,4 @@
1
1
  /* eslint-disable */
2
- import type {
3
- JsonObject,
4
- JsonReadOptions,
5
- JsonValue,
6
- JsonWriteOptions,
7
- } from '@protobuf-ts/runtime';
8
2
  // @generated by protobuf-ts 2.10.0 with parameter long_type_string,client_generic,server_none,eslint_disable,optimize_code_size
9
3
  // @generated from protobuf file "google/protobuf/struct.proto" (package "google.protobuf", syntax proto3)
10
4
  // tslint:disable
@@ -39,12 +33,13 @@ import type {
39
33
  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40
34
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41
35
  //
42
- import {
43
- isJsonObject,
44
- MessageType,
45
- typeofJsonValue,
46
- } from '@protobuf-ts/runtime';
47
-
36
+ import { isJsonObject } from '@protobuf-ts/runtime';
37
+ import { typeofJsonValue } from '@protobuf-ts/runtime';
38
+ import type { JsonValue } from '@protobuf-ts/runtime';
39
+ import type { JsonReadOptions } from '@protobuf-ts/runtime';
40
+ import type { JsonWriteOptions } from '@protobuf-ts/runtime';
41
+ import type { JsonObject } from '@protobuf-ts/runtime';
42
+ import { MessageType } from '@protobuf-ts/runtime';
48
43
  /**
49
44
  * `Struct` represents a structured data value, consisting of fields
50
45
  * which map to dynamically typed values. In some languages, `Struct`
@@ -1,9 +1,4 @@
1
1
  /* eslint-disable */
2
- import type {
3
- JsonReadOptions,
4
- JsonValue,
5
- JsonWriteOptions,
6
- } from '@protobuf-ts/runtime';
7
2
  // @generated by protobuf-ts 2.10.0 with parameter long_type_string,client_generic,server_none,eslint_disable,optimize_code_size
8
3
  // @generated from protobuf file "google/protobuf/timestamp.proto" (package "google.protobuf", syntax proto3)
9
4
  // tslint:disable
@@ -38,8 +33,12 @@ import type {
38
33
  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39
34
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
35
  //
41
- import { MessageType, PbLong, typeofJsonValue } from '@protobuf-ts/runtime';
42
-
36
+ import { typeofJsonValue } from '@protobuf-ts/runtime';
37
+ import type { JsonValue } from '@protobuf-ts/runtime';
38
+ import type { JsonReadOptions } from '@protobuf-ts/runtime';
39
+ import type { JsonWriteOptions } from '@protobuf-ts/runtime';
40
+ import { PbLong } from '@protobuf-ts/runtime';
41
+ import { MessageType } from '@protobuf-ts/runtime';
43
42
  /**
44
43
  * A Timestamp represents a point in time independent of any time zone or local
45
44
  * calendar, encoded as a count of seconds and fractions of seconds at
@@ -2,32 +2,29 @@
2
2
  // @generated from protobuf file "video/sfu/event/events.proto" (package "stream.video.sfu.event", syntax proto3)
3
3
  // tslint:disable
4
4
  import { MessageType } from '@protobuf-ts/runtime';
5
- import {
6
- CallEndedReason,
7
- CallGrants,
8
- CallState,
9
- ClientCapability,
10
- ClientDetails,
11
- Codec,
12
- ConnectionQuality,
13
- DegradationPreference,
14
- Error as Error$,
15
- GoAwayReason,
16
- ICETrickle as ICETrickle$,
17
- Participant,
18
- ParticipantCount,
19
- ParticipantSource,
20
- PeerType,
21
- Pin,
22
- PublishOption,
23
- SubscribeOption,
24
- TrackInfo,
25
- TrackType,
26
- TrackUnpublishReason,
27
- WebsocketReconnectStrategy,
28
- } from '../models/models';
5
+ import { CallEndedReason } from '../models/models';
6
+ import { GoAwayReason } from '../models/models';
7
+ import { CallGrants } from '../models/models';
8
+ import { DegradationPreference } from '../models/models';
9
+ import { Codec } from '../models/models';
10
+ import { ConnectionQuality } from '../models/models';
11
+ import { CallState } from '../models/models';
29
12
  import { TrackSubscriptionDetails } from '../signal_rpc/signal';
30
-
13
+ import { TrackInfo } from '../models/models';
14
+ import { ParticipantSource } from '../models/models';
15
+ import { ClientCapability } from '../models/models';
16
+ import { SubscribeOption } from '../models/models';
17
+ import { ClientDetails } from '../models/models';
18
+ import { TrackUnpublishReason } from '../models/models';
19
+ import { Participant } from '../models/models';
20
+ import { TrackType } from '../models/models';
21
+ import { ParticipantCount } from '../models/models';
22
+ import { PeerType } from '../models/models';
23
+ import { WebsocketReconnectStrategy } from '../models/models';
24
+ import { Error as Error$ } from '../models/models';
25
+ import { Pin } from '../models/models';
26
+ import { PublishOption } from '../models/models';
27
+ import { ICETrickle as ICETrickle$ } from '../models/models';
31
28
  /**
32
29
  * SFUEvent is a message that is sent from the SFU to the client.
33
30
  *
@@ -4,7 +4,6 @@
4
4
  import { MessageType } from '@protobuf-ts/runtime';
5
5
  import { Struct } from '../../../google/protobuf/struct';
6
6
  import { Timestamp } from '../../../google/protobuf/timestamp';
7
-
8
7
  /**
9
8
  * CallState is the current state of the call
10
9
  * as seen by an SFU.
@@ -415,6 +414,10 @@ export interface TrackInfo {
415
414
  * @generated from protobuf field: int32 publish_option_id = 12;
416
415
  */
417
416
  publishOptionId: number;
417
+ /**
418
+ * @generated from protobuf field: bool self_sub_audio_video = 13;
419
+ */
420
+ selfSubAudioVideo: boolean;
418
421
  }
419
422
  /**
420
423
  * @generated from protobuf message stream.video.sfu.models.Error
@@ -1770,6 +1773,12 @@ class TrackInfo$Type extends MessageType<TrackInfo> {
1770
1773
  kind: 'scalar',
1771
1774
  T: 5 /*ScalarType.INT32*/,
1772
1775
  },
1776
+ {
1777
+ no: 13,
1778
+ name: 'self_sub_audio_video',
1779
+ kind: 'scalar',
1780
+ T: 8 /*ScalarType.BOOL*/,
1781
+ },
1773
1782
  ]);
1774
1783
  }
1775
1784
  }
@@ -1,37 +1,32 @@
1
1
  // @generated by protobuf-ts 2.10.0 with parameter long_type_string,client_generic,server_none,eslint_disable,optimize_code_size
2
2
  // @generated from protobuf file "video/sfu/signal_rpc/signal.proto" (package "stream.video.sfu.signal", syntax proto3)
3
3
  // tslint:disable
4
- import type {
5
- RpcOptions,
6
- RpcTransport,
7
- ServiceInfo,
8
- UnaryCall,
9
- } from '@protobuf-ts/runtime-rpc';
10
- import { stackIntercept } from '@protobuf-ts/runtime-rpc';
11
- import type {
12
- ICERestartRequest,
13
- ICERestartResponse,
14
- ICETrickleResponse,
15
- SendAnswerRequest,
16
- SendAnswerResponse,
17
- SendMetricsRequest,
18
- SendMetricsResponse,
19
- SendStatsRequest,
20
- SendStatsResponse,
21
- SetPublisherRequest,
22
- SetPublisherResponse,
23
- StartNoiseCancellationRequest,
24
- StartNoiseCancellationResponse,
25
- StopNoiseCancellationRequest,
26
- StopNoiseCancellationResponse,
27
- UpdateMuteStatesRequest,
28
- UpdateMuteStatesResponse,
29
- UpdateSubscriptionsRequest,
30
- UpdateSubscriptionsResponse,
31
- } from './signal';
4
+ import type { RpcTransport } from '@protobuf-ts/runtime-rpc';
5
+ import type { ServiceInfo } from '@protobuf-ts/runtime-rpc';
32
6
  import { SignalServer } from './signal';
7
+ import type { StopNoiseCancellationResponse } from './signal';
8
+ import type { StopNoiseCancellationRequest } from './signal';
9
+ import type { StartNoiseCancellationResponse } from './signal';
10
+ import type { StartNoiseCancellationRequest } from './signal';
11
+ import type { SendMetricsResponse } from './signal';
12
+ import type { SendMetricsRequest } from './signal';
13
+ import type { SendStatsResponse } from './signal';
14
+ import type { SendStatsRequest } from './signal';
15
+ import type { ICERestartResponse } from './signal';
16
+ import type { ICERestartRequest } from './signal';
17
+ import type { UpdateMuteStatesResponse } from './signal';
18
+ import type { UpdateMuteStatesRequest } from './signal';
19
+ import type { UpdateSubscriptionsResponse } from './signal';
20
+ import type { UpdateSubscriptionsRequest } from './signal';
21
+ import type { ICETrickleResponse } from './signal';
33
22
  import type { ICETrickle } from '../models/models';
34
-
23
+ import type { SendAnswerResponse } from './signal';
24
+ import type { SendAnswerRequest } from './signal';
25
+ import { stackIntercept } from '@protobuf-ts/runtime-rpc';
26
+ import type { SetPublisherResponse } from './signal';
27
+ import type { SetPublisherRequest } from './signal';
28
+ import type { UnaryCall } from '@protobuf-ts/runtime-rpc';
29
+ import type { RpcOptions } from '@protobuf-ts/runtime-rpc';
35
30
  /**
36
31
  * @generated from protobuf service stream.video.sfu.signal.SignalServer
37
32
  */
@@ -93,6 +93,7 @@ export class MediaPlaybackWatchdog {
93
93
  const HAVE_CURRENT_DATA = 2;
94
94
  if (this.element.readyState < HAVE_CURRENT_DATA) return 'notReady';
95
95
  if (!this.element.paused) return 'notPaused';
96
+ return undefined;
96
97
  };
97
98
 
98
99
  private attemptPlay = async () => {