livekit-client 0.17.4 → 0.17.6-rc2

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 (155) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +26 -20
  3. package/dist/api/SignalClient.d.ts +1 -0
  4. package/dist/connect.d.ts +2 -0
  5. package/dist/index.d.ts +2 -2
  6. package/dist/livekit-client.esm.js +17344 -0
  7. package/dist/livekit-client.esm.js.map +1 -0
  8. package/dist/livekit-client.umd.js +2 -0
  9. package/dist/livekit-client.umd.js.map +1 -0
  10. package/dist/logger.d.ts +22 -11
  11. package/dist/options.d.ts +4 -2
  12. package/dist/proto/google/protobuf/timestamp.d.ts +12 -2
  13. package/dist/proto/livekit_models.d.ts +524 -17
  14. package/dist/proto/livekit_rtc.d.ts +3449 -31
  15. package/dist/room/DeviceManager.d.ts +1 -1
  16. package/dist/room/RTCEngine.d.ts +1 -1
  17. package/dist/room/Room.d.ts +2 -2
  18. package/dist/room/events.d.ts +1 -1
  19. package/dist/room/participant/LocalParticipant.d.ts +9 -5
  20. package/dist/room/participant/RemoteParticipant.d.ts +9 -0
  21. package/dist/room/track/RemoteAudioTrack.d.ts +11 -0
  22. package/dist/room/track/options.d.ts +1 -1
  23. package/dist/test/mocks.d.ts +11 -0
  24. package/dist/version.d.ts +1 -1
  25. package/package.json +41 -16
  26. package/.eslintrc.js +0 -17
  27. package/.gitmodules +0 -3
  28. package/dist/api/RequestQueue.js +0 -61
  29. package/dist/api/RequestQueue.js.map +0 -1
  30. package/dist/api/SignalClient.js +0 -428
  31. package/dist/api/SignalClient.js.map +0 -1
  32. package/dist/connect.js +0 -130
  33. package/dist/connect.js.map +0 -1
  34. package/dist/index.js +0 -71
  35. package/dist/index.js.map +0 -1
  36. package/dist/logger.js +0 -24
  37. package/dist/logger.js.map +0 -1
  38. package/dist/options.js +0 -3
  39. package/dist/options.js.map +0 -1
  40. package/dist/proto/google/protobuf/timestamp.js +0 -93
  41. package/dist/proto/google/protobuf/timestamp.js.map +0 -1
  42. package/dist/proto/livekit_models.js +0 -2688
  43. package/dist/proto/livekit_models.js.map +0 -1
  44. package/dist/proto/livekit_rtc.js +0 -2995
  45. package/dist/proto/livekit_rtc.js.map +0 -1
  46. package/dist/room/DeviceManager.js +0 -62
  47. package/dist/room/DeviceManager.js.map +0 -1
  48. package/dist/room/PCTransport.js +0 -91
  49. package/dist/room/PCTransport.js.map +0 -1
  50. package/dist/room/RTCEngine.js +0 -562
  51. package/dist/room/RTCEngine.js.map +0 -1
  52. package/dist/room/Room.js +0 -759
  53. package/dist/room/Room.js.map +0 -1
  54. package/dist/room/errors.js +0 -68
  55. package/dist/room/errors.js.map +0 -1
  56. package/dist/room/events.js +0 -385
  57. package/dist/room/events.js.map +0 -1
  58. package/dist/room/participant/LocalParticipant.js +0 -647
  59. package/dist/room/participant/LocalParticipant.js.map +0 -1
  60. package/dist/room/participant/Participant.js +0 -189
  61. package/dist/room/participant/Participant.js.map +0 -1
  62. package/dist/room/participant/ParticipantTrackPermission.js +0 -16
  63. package/dist/room/participant/ParticipantTrackPermission.js.map +0 -1
  64. package/dist/room/participant/RemoteParticipant.js +0 -194
  65. package/dist/room/participant/RemoteParticipant.js.map +0 -1
  66. package/dist/room/participant/publishUtils.js +0 -189
  67. package/dist/room/participant/publishUtils.js.map +0 -1
  68. package/dist/room/participant/publishUtils.test.d.ts +0 -1
  69. package/dist/room/participant/publishUtils.test.js +0 -118
  70. package/dist/room/participant/publishUtils.test.js.map +0 -1
  71. package/dist/room/stats.js +0 -26
  72. package/dist/room/stats.js.map +0 -1
  73. package/dist/room/track/LocalAudioTrack.js +0 -153
  74. package/dist/room/track/LocalAudioTrack.js.map +0 -1
  75. package/dist/room/track/LocalTrack.js +0 -158
  76. package/dist/room/track/LocalTrack.js.map +0 -1
  77. package/dist/room/track/LocalTrackPublication.js +0 -64
  78. package/dist/room/track/LocalTrackPublication.js.map +0 -1
  79. package/dist/room/track/LocalVideoTrack.js +0 -297
  80. package/dist/room/track/LocalVideoTrack.js.map +0 -1
  81. package/dist/room/track/LocalVideoTrack.test.d.ts +0 -1
  82. package/dist/room/track/LocalVideoTrack.test.js +0 -68
  83. package/dist/room/track/LocalVideoTrack.test.js.map +0 -1
  84. package/dist/room/track/RemoteAudioTrack.js +0 -64
  85. package/dist/room/track/RemoteAudioTrack.js.map +0 -1
  86. package/dist/room/track/RemoteTrack.js +0 -49
  87. package/dist/room/track/RemoteTrack.js.map +0 -1
  88. package/dist/room/track/RemoteTrackPublication.js +0 -178
  89. package/dist/room/track/RemoteTrackPublication.js.map +0 -1
  90. package/dist/room/track/RemoteVideoTrack.js +0 -201
  91. package/dist/room/track/RemoteVideoTrack.js.map +0 -1
  92. package/dist/room/track/Track.js +0 -283
  93. package/dist/room/track/Track.js.map +0 -1
  94. package/dist/room/track/TrackPublication.js +0 -92
  95. package/dist/room/track/TrackPublication.js.map +0 -1
  96. package/dist/room/track/create.js +0 -131
  97. package/dist/room/track/create.js.map +0 -1
  98. package/dist/room/track/defaults.js +0 -21
  99. package/dist/room/track/defaults.js.map +0 -1
  100. package/dist/room/track/options.js +0 -100
  101. package/dist/room/track/options.js.map +0 -1
  102. package/dist/room/track/types.js +0 -3
  103. package/dist/room/track/types.js.map +0 -1
  104. package/dist/room/track/utils.js +0 -113
  105. package/dist/room/track/utils.js.map +0 -1
  106. package/dist/room/track/utils.test.d.ts +0 -1
  107. package/dist/room/track/utils.test.js +0 -85
  108. package/dist/room/track/utils.test.js.map +0 -1
  109. package/dist/room/utils.js +0 -79
  110. package/dist/room/utils.js.map +0 -1
  111. package/dist/version.js +0 -6
  112. package/dist/version.js.map +0 -1
  113. package/jest.config.js +0 -6
  114. package/src/api/RequestQueue.ts +0 -53
  115. package/src/api/SignalClient.ts +0 -499
  116. package/src/connect.ts +0 -100
  117. package/src/index.ts +0 -47
  118. package/src/logger.ts +0 -22
  119. package/src/options.ts +0 -149
  120. package/src/proto/google/protobuf/timestamp.ts +0 -222
  121. package/src/proto/livekit_models.ts +0 -3019
  122. package/src/proto/livekit_rtc.ts +0 -3677
  123. package/src/room/DeviceManager.ts +0 -57
  124. package/src/room/PCTransport.ts +0 -86
  125. package/src/room/RTCEngine.ts +0 -652
  126. package/src/room/Room.ts +0 -943
  127. package/src/room/errors.ts +0 -65
  128. package/src/room/events.ts +0 -424
  129. package/src/room/participant/LocalParticipant.ts +0 -734
  130. package/src/room/participant/Participant.ts +0 -269
  131. package/src/room/participant/ParticipantTrackPermission.ts +0 -32
  132. package/src/room/participant/RemoteParticipant.ts +0 -243
  133. package/src/room/participant/publishUtils.test.ts +0 -145
  134. package/src/room/participant/publishUtils.ts +0 -225
  135. package/src/room/stats.ts +0 -130
  136. package/src/room/track/LocalAudioTrack.ts +0 -137
  137. package/src/room/track/LocalTrack.ts +0 -161
  138. package/src/room/track/LocalTrackPublication.ts +0 -66
  139. package/src/room/track/LocalVideoTrack.test.ts +0 -70
  140. package/src/room/track/LocalVideoTrack.ts +0 -293
  141. package/src/room/track/RemoteAudioTrack.ts +0 -58
  142. package/src/room/track/RemoteTrack.ts +0 -62
  143. package/src/room/track/RemoteTrackPublication.ts +0 -198
  144. package/src/room/track/RemoteVideoTrack.ts +0 -235
  145. package/src/room/track/Track.ts +0 -343
  146. package/src/room/track/TrackPublication.ts +0 -120
  147. package/src/room/track/create.ts +0 -121
  148. package/src/room/track/defaults.ts +0 -23
  149. package/src/room/track/options.ts +0 -281
  150. package/src/room/track/types.ts +0 -20
  151. package/src/room/track/utils.test.ts +0 -93
  152. package/src/room/track/utils.ts +0 -115
  153. package/src/room/utils.ts +0 -70
  154. package/src/version.ts +0 -2
  155. package/tsconfig.eslint.json +0 -11
package/dist/room/Room.js DELETED
@@ -1,759 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
22
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
23
- return new (P || (P = Promise))(function (resolve, reject) {
24
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
25
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
26
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
27
- step((generator = generator.apply(thisArg, _arguments || [])).next());
28
- });
29
- };
30
- var __importDefault = (this && this.__importDefault) || function (mod) {
31
- return (mod && mod.__esModule) ? mod : { "default": mod };
32
- };
33
- Object.defineProperty(exports, "__esModule", { value: true });
34
- exports.RoomState = void 0;
35
- const events_1 = require("events");
36
- const SignalClient_1 = require("../api/SignalClient");
37
- const logger_1 = __importDefault(require("../logger"));
38
- const livekit_models_1 = require("../proto/livekit_models");
39
- const livekit_rtc_1 = require("../proto/livekit_rtc");
40
- const DeviceManager_1 = __importDefault(require("./DeviceManager"));
41
- const errors_1 = require("./errors");
42
- const events_2 = require("./events");
43
- const LocalParticipant_1 = __importDefault(require("./participant/LocalParticipant"));
44
- const RemoteParticipant_1 = __importDefault(require("./participant/RemoteParticipant"));
45
- const RTCEngine_1 = __importStar(require("./RTCEngine"));
46
- const defaults_1 = require("./track/defaults");
47
- const RemoteTrackPublication_1 = __importDefault(require("./track/RemoteTrackPublication"));
48
- const Track_1 = require("./track/Track");
49
- const utils_1 = require("./track/utils");
50
- const utils_2 = require("./utils");
51
- var RoomState;
52
- (function (RoomState) {
53
- RoomState["Disconnected"] = "disconnected";
54
- RoomState["Connected"] = "connected";
55
- RoomState["Reconnecting"] = "reconnecting";
56
- })(RoomState = exports.RoomState || (exports.RoomState = {}));
57
- /**
58
- * In LiveKit, a room is the logical grouping for a list of participants.
59
- * Participants in a room can publish tracks, and subscribe to others' tracks.
60
- *
61
- * a Room fires [[RoomEvent | RoomEvents]].
62
- *
63
- * @noInheritDoc
64
- */
65
- class Room extends events_1.EventEmitter {
66
- /**
67
- * Creates a new Room, the primary construct for a LiveKit session.
68
- * @param options
69
- */
70
- constructor(options) {
71
- super();
72
- this.state = RoomState.Disconnected;
73
- /**
74
- * list of participants that are actively speaking. when this changes
75
- * a [[RoomEvent.ActiveSpeakersChanged]] event is fired
76
- */
77
- this.activeSpeakers = [];
78
- // available after connected
79
- /** server assigned unique room id */
80
- this.sid = '';
81
- /** user assigned name, derived from JWT token */
82
- this.name = '';
83
- /** room metadata */
84
- this.metadata = undefined;
85
- this.audioEnabled = true;
86
- this.connect = (url, token, opts) => __awaiter(this, void 0, void 0, function* () {
87
- // guard against calling connect
88
- if (this.state !== RoomState.Disconnected) {
89
- logger_1.default.warn('already connected to room', this.name);
90
- return;
91
- }
92
- // recreate engine if previously disconnected
93
- this.createEngine();
94
- this.acquireAudioContext();
95
- if (opts === null || opts === void 0 ? void 0 : opts.rtcConfig) {
96
- this.engine.rtcConfig = opts.rtcConfig;
97
- }
98
- this.connOptions = opts;
99
- try {
100
- const joinResponse = yield this.engine.join(url, token, opts);
101
- logger_1.default.debug(`connected to Livekit Server version: ${joinResponse.serverVersion}, region: ${joinResponse.serverRegion}`);
102
- if (!joinResponse.serverVersion) {
103
- throw new errors_1.UnsupportedServer('unknown server version');
104
- }
105
- if (joinResponse.serverVersion === '0.15.1' && this.options.dynacast) {
106
- logger_1.default.debug('disabling dynacast due to server version');
107
- // dynacast has a bug in 0.15.1, so we cannot use it then
108
- this.options.dynacast = false;
109
- }
110
- this.state = RoomState.Connected;
111
- this.emit(events_2.RoomEvent.StateChanged, this.state);
112
- const pi = joinResponse.participant;
113
- this.localParticipant.sid = pi.sid;
114
- this.localParticipant.identity = pi.identity;
115
- this.localParticipant.updateInfo(pi);
116
- // forward metadata changed for the local participant
117
- this.localParticipant
118
- .on(events_2.ParticipantEvent.MetadataChanged, (metadata) => {
119
- this.emit(events_2.RoomEvent.MetadataChanged, metadata, this.localParticipant);
120
- })
121
- .on(events_2.ParticipantEvent.ParticipantMetadataChanged, (metadata) => {
122
- this.emit(events_2.RoomEvent.ParticipantMetadataChanged, metadata, this.localParticipant);
123
- })
124
- .on(events_2.ParticipantEvent.TrackMuted, (pub) => {
125
- this.emit(events_2.RoomEvent.TrackMuted, pub, this.localParticipant);
126
- })
127
- .on(events_2.ParticipantEvent.TrackUnmuted, (pub) => {
128
- this.emit(events_2.RoomEvent.TrackUnmuted, pub, this.localParticipant);
129
- })
130
- .on(events_2.ParticipantEvent.LocalTrackPublished, (pub) => {
131
- this.emit(events_2.RoomEvent.LocalTrackPublished, pub, this.localParticipant);
132
- })
133
- .on(events_2.ParticipantEvent.LocalTrackUnpublished, (pub) => {
134
- this.emit(events_2.RoomEvent.LocalTrackUnpublished, pub, this.localParticipant);
135
- })
136
- .on(events_2.ParticipantEvent.ConnectionQualityChanged, (quality) => {
137
- this.emit(events_2.RoomEvent.ConnectionQualityChanged, quality, this.localParticipant);
138
- })
139
- .on(events_2.ParticipantEvent.MediaDevicesError, (e) => {
140
- this.emit(events_2.RoomEvent.MediaDevicesError, e);
141
- })
142
- .on(events_2.ParticipantEvent.ParticipantPermissionsChanged, (prevPermissions) => {
143
- this.emit(events_2.RoomEvent.ParticipantPermissionsChanged, prevPermissions, this.localParticipant);
144
- });
145
- // populate remote participants, these should not trigger new events
146
- joinResponse.otherParticipants.forEach((info) => {
147
- this.getOrCreateParticipant(info.sid, info);
148
- });
149
- this.name = joinResponse.room.name;
150
- this.sid = joinResponse.room.sid;
151
- this.metadata = joinResponse.room.metadata;
152
- }
153
- catch (err) {
154
- this.engine.close();
155
- throw err;
156
- }
157
- // don't return until ICE connected
158
- return new Promise((resolve, reject) => {
159
- const connectTimeout = setTimeout(() => {
160
- // timeout
161
- this.engine.close();
162
- reject(new errors_1.ConnectionError('could not connect after timeout'));
163
- }, RTCEngine_1.maxICEConnectTimeout);
164
- this.engine.once(events_2.EngineEvent.Connected, () => {
165
- clearTimeout(connectTimeout);
166
- // also hook unload event
167
- if (utils_2.isWeb()) {
168
- window.addEventListener('beforeunload', this.onBeforeUnload);
169
- navigator.mediaDevices.addEventListener('devicechange', this.handleDeviceChange);
170
- }
171
- resolve(this);
172
- });
173
- });
174
- });
175
- /**
176
- * disconnects the room, emits [[RoomEvent.Disconnected]]
177
- */
178
- this.disconnect = (stopTracks = true) => {
179
- // send leave
180
- if (this.engine) {
181
- this.engine.client.sendLeave();
182
- this.engine.close();
183
- }
184
- this.handleDisconnect(stopTracks);
185
- /* @ts-ignore */
186
- this.engine = undefined;
187
- };
188
- this.onBeforeUnload = () => {
189
- this.disconnect();
190
- };
191
- this.handleRestarting = () => {
192
- this.state = RoomState.Reconnecting;
193
- this.emit(events_2.RoomEvent.Reconnecting);
194
- this.emit(events_2.RoomEvent.StateChanged, this.state);
195
- // also unwind existing participants & existing subscriptions
196
- for (const p of this.participants.values()) {
197
- this.handleParticipantDisconnected(p.sid, p);
198
- }
199
- };
200
- this.handleRestarted = (joinResponse) => __awaiter(this, void 0, void 0, function* () {
201
- logger_1.default.debug('reconnected to server region', joinResponse.serverRegion);
202
- this.state = RoomState.Connected;
203
- this.emit(events_2.RoomEvent.Reconnected);
204
- this.emit(events_2.RoomEvent.StateChanged, this.state);
205
- // rehydrate participants
206
- if (joinResponse.participant) {
207
- // with a restart, the sid will have changed, we'll map our understanding to it
208
- this.localParticipant.sid = joinResponse.participant.sid;
209
- this.handleParticipantUpdates([joinResponse.participant]);
210
- }
211
- this.handleParticipantUpdates(joinResponse.otherParticipants);
212
- // unpublish & republish tracks
213
- const localPubs = [];
214
- this.localParticipant.tracks.forEach((pub) => {
215
- if (pub.track) {
216
- localPubs.push(pub);
217
- }
218
- });
219
- yield Promise.all(localPubs.map((pub) => __awaiter(this, void 0, void 0, function* () {
220
- const track = pub.track;
221
- this.localParticipant.unpublishTrack(track, false);
222
- this.localParticipant.publishTrack(track, pub.options);
223
- })));
224
- });
225
- this.handleParticipantUpdates = (participantInfos) => {
226
- // handle changes to participant state, and send events
227
- participantInfos.forEach((info) => {
228
- if (info.sid === this.localParticipant.sid
229
- || info.identity === this.localParticipant.identity) {
230
- this.localParticipant.updateInfo(info);
231
- return;
232
- }
233
- let remoteParticipant = this.participants.get(info.sid);
234
- const isNewParticipant = !remoteParticipant;
235
- // create participant if doesn't exist
236
- remoteParticipant = this.getOrCreateParticipant(info.sid, info);
237
- // when it's disconnected, send updates
238
- if (info.state === livekit_models_1.ParticipantInfo_State.DISCONNECTED) {
239
- this.handleParticipantDisconnected(info.sid, remoteParticipant);
240
- }
241
- else if (isNewParticipant) {
242
- // fire connected event
243
- this.emit(events_2.RoomEvent.ParticipantConnected, remoteParticipant);
244
- }
245
- else {
246
- // just update, no events
247
- remoteParticipant.updateInfo(info);
248
- }
249
- });
250
- };
251
- // updates are sent only when there's a change to speaker ordering
252
- this.handleActiveSpeakersUpdate = (speakers) => {
253
- const activeSpeakers = [];
254
- const seenSids = {};
255
- speakers.forEach((speaker) => {
256
- seenSids[speaker.sid] = true;
257
- if (speaker.sid === this.localParticipant.sid) {
258
- this.localParticipant.audioLevel = speaker.level;
259
- this.localParticipant.setIsSpeaking(true);
260
- activeSpeakers.push(this.localParticipant);
261
- }
262
- else {
263
- const p = this.participants.get(speaker.sid);
264
- if (p) {
265
- p.audioLevel = speaker.level;
266
- p.setIsSpeaking(true);
267
- activeSpeakers.push(p);
268
- }
269
- }
270
- });
271
- if (!seenSids[this.localParticipant.sid]) {
272
- this.localParticipant.audioLevel = 0;
273
- this.localParticipant.setIsSpeaking(false);
274
- }
275
- this.participants.forEach((p) => {
276
- if (!seenSids[p.sid]) {
277
- p.audioLevel = 0;
278
- p.setIsSpeaking(false);
279
- }
280
- });
281
- this.activeSpeakers = activeSpeakers;
282
- this.emit(events_2.RoomEvent.ActiveSpeakersChanged, activeSpeakers);
283
- };
284
- // process list of changed speakers
285
- this.handleSpeakersChanged = (speakerUpdates) => {
286
- const lastSpeakers = new Map();
287
- this.activeSpeakers.forEach((p) => {
288
- lastSpeakers.set(p.sid, p);
289
- });
290
- speakerUpdates.forEach((speaker) => {
291
- let p = this.participants.get(speaker.sid);
292
- if (speaker.sid === this.localParticipant.sid) {
293
- p = this.localParticipant;
294
- }
295
- if (!p) {
296
- return;
297
- }
298
- p.audioLevel = speaker.level;
299
- p.setIsSpeaking(speaker.active);
300
- if (speaker.active) {
301
- lastSpeakers.set(speaker.sid, p);
302
- }
303
- else {
304
- lastSpeakers.delete(speaker.sid);
305
- }
306
- });
307
- const activeSpeakers = Array.from(lastSpeakers.values());
308
- activeSpeakers.sort((a, b) => b.audioLevel - a.audioLevel);
309
- this.activeSpeakers = activeSpeakers;
310
- this.emit(events_2.RoomEvent.ActiveSpeakersChanged, activeSpeakers);
311
- };
312
- this.handleStreamStateUpdate = (streamStateUpdate) => {
313
- streamStateUpdate.streamStates.forEach((streamState) => {
314
- const participant = this.participants.get(streamState.participantSid);
315
- if (!participant) {
316
- return;
317
- }
318
- const pub = participant.getTrackPublication(streamState.trackSid);
319
- if (!pub || !pub.track) {
320
- return;
321
- }
322
- pub.track.streamState = Track_1.Track.streamStateFromProto(streamState.state);
323
- participant.emit(events_2.ParticipantEvent.TrackStreamStateChanged, pub, pub.track.streamState);
324
- this.emit(events_2.ParticipantEvent.TrackStreamStateChanged, pub, pub.track.streamState, participant);
325
- });
326
- };
327
- this.handleSubscriptionPermissionUpdate = (update) => {
328
- const participant = this.participants.get(update.participantSid);
329
- if (!participant) {
330
- return;
331
- }
332
- const pub = participant.getTrackPublication(update.trackSid);
333
- if (!pub) {
334
- return;
335
- }
336
- pub._allowed = update.allowed;
337
- participant.emit(events_2.ParticipantEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus);
338
- this.emit(events_2.ParticipantEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus, participant);
339
- };
340
- this.handleDataPacket = (userPacket, kind) => {
341
- // find the participant
342
- const participant = this.participants.get(userPacket.participantSid);
343
- this.emit(events_2.RoomEvent.DataReceived, userPacket.payload, participant, kind);
344
- // also emit on the participant
345
- participant === null || participant === void 0 ? void 0 : participant.emit(events_2.ParticipantEvent.DataReceived, userPacket.payload, kind);
346
- };
347
- this.handleAudioPlaybackStarted = () => {
348
- if (this.canPlaybackAudio) {
349
- return;
350
- }
351
- this.audioEnabled = true;
352
- this.emit(events_2.RoomEvent.AudioPlaybackStatusChanged, true);
353
- };
354
- this.handleAudioPlaybackFailed = (e) => {
355
- logger_1.default.warn('could not playback audio', e);
356
- if (!this.canPlaybackAudio) {
357
- return;
358
- }
359
- this.audioEnabled = false;
360
- this.emit(events_2.RoomEvent.AudioPlaybackStatusChanged, false);
361
- };
362
- this.handleDeviceChange = () => __awaiter(this, void 0, void 0, function* () {
363
- this.emit(events_2.RoomEvent.MediaDevicesChanged);
364
- });
365
- this.handleRoomUpdate = (r) => {
366
- this.metadata = r.metadata;
367
- this.emit(events_2.RoomEvent.RoomMetadataChanged, r.metadata);
368
- };
369
- this.handleConnectionQualityUpdate = (update) => {
370
- update.updates.forEach((info) => {
371
- if (info.participantSid === this.localParticipant.sid) {
372
- this.localParticipant.setConnectionQuality(info.quality);
373
- return;
374
- }
375
- const participant = this.participants.get(info.participantSid);
376
- if (participant) {
377
- participant.setConnectionQuality(info.quality);
378
- }
379
- });
380
- };
381
- this.participants = new Map();
382
- this.options = options || {};
383
- this.options.audioCaptureDefaults = Object.assign(Object.assign({}, defaults_1.audioDefaults), options === null || options === void 0 ? void 0 : options.audioCaptureDefaults);
384
- this.options.videoCaptureDefaults = Object.assign(Object.assign({}, defaults_1.videoDefaults), options === null || options === void 0 ? void 0 : options.videoCaptureDefaults);
385
- this.options.publishDefaults = Object.assign(Object.assign({}, defaults_1.publishDefaults), options === null || options === void 0 ? void 0 : options.publishDefaults);
386
- this.createEngine();
387
- this.localParticipant = new LocalParticipant_1.default('', '', this.engine, this.options);
388
- }
389
- createEngine() {
390
- if (this.engine) {
391
- return;
392
- }
393
- this.engine = new RTCEngine_1.default();
394
- this.engine.client.signalLatency = this.options.expSignalLatency;
395
- this.engine.client.onParticipantUpdate = this.handleParticipantUpdates;
396
- this.engine.client.onRoomUpdate = this.handleRoomUpdate;
397
- this.engine.client.onSpeakersChanged = this.handleSpeakersChanged;
398
- this.engine.client.onStreamStateUpdate = this.handleStreamStateUpdate;
399
- this.engine.client.onSubscriptionPermissionUpdate = this.handleSubscriptionPermissionUpdate;
400
- this.engine.client.onConnectionQuality = this.handleConnectionQualityUpdate;
401
- this.engine
402
- .on(events_2.EngineEvent.MediaTrackAdded, (mediaTrack, stream, receiver) => {
403
- this.onTrackAdded(mediaTrack, stream, receiver);
404
- })
405
- .on(events_2.EngineEvent.Disconnected, () => {
406
- this.handleDisconnect();
407
- })
408
- .on(events_2.EngineEvent.ActiveSpeakersUpdate, this.handleActiveSpeakersUpdate)
409
- .on(events_2.EngineEvent.DataPacketReceived, this.handleDataPacket)
410
- .on(events_2.EngineEvent.Resuming, () => {
411
- this.state = RoomState.Reconnecting;
412
- this.emit(events_2.RoomEvent.Reconnecting);
413
- this.emit(events_2.RoomEvent.StateChanged, this.state);
414
- })
415
- .on(events_2.EngineEvent.Resumed, () => {
416
- this.state = RoomState.Connected;
417
- this.emit(events_2.RoomEvent.Reconnected);
418
- this.emit(events_2.RoomEvent.StateChanged, this.state);
419
- this.updateSubscriptions();
420
- })
421
- .on(events_2.EngineEvent.SignalResumed, () => {
422
- if (this.state === RoomState.Reconnecting) {
423
- this.sendSyncState();
424
- }
425
- })
426
- .on(events_2.EngineEvent.Restarting, this.handleRestarting)
427
- .on(events_2.EngineEvent.Restarted, this.handleRestarted);
428
- }
429
- /**
430
- * getLocalDevices abstracts navigator.mediaDevices.enumerateDevices.
431
- * In particular, it handles Chrome's unique behavior of creating `default`
432
- * devices. When encountered, it'll be removed from the list of devices.
433
- * The actual default device will be placed at top.
434
- * @param kind
435
- * @returns a list of available local devices
436
- */
437
- static getLocalDevices(kind) {
438
- return DeviceManager_1.default.getInstance().getDevices(kind);
439
- }
440
- /**
441
- * retrieves a participant by identity
442
- * @param identity
443
- * @returns
444
- */
445
- getParticipantByIdentity(identity) {
446
- for (const [, p] of this.participants) {
447
- if (p.identity === identity) {
448
- return p;
449
- }
450
- }
451
- if (this.localParticipant.identity === identity) {
452
- return this.localParticipant;
453
- }
454
- }
455
- /**
456
- * @internal for testing
457
- */
458
- simulateScenario(scenario) {
459
- let req;
460
- switch (scenario) {
461
- case 'speaker':
462
- req = livekit_rtc_1.SimulateScenario.fromPartial({
463
- speakerUpdate: 3,
464
- });
465
- break;
466
- case 'node-failure':
467
- req = livekit_rtc_1.SimulateScenario.fromPartial({
468
- nodeFailure: true,
469
- });
470
- break;
471
- case 'server-leave':
472
- req = livekit_rtc_1.SimulateScenario.fromPartial({
473
- serverLeave: true,
474
- });
475
- break;
476
- case 'migration':
477
- req = livekit_rtc_1.SimulateScenario.fromPartial({
478
- migration: true,
479
- });
480
- break;
481
- default:
482
- }
483
- if (req) {
484
- this.engine.client.sendSimulateScenario(req);
485
- }
486
- }
487
- /**
488
- * Browsers have different policies regarding audio playback. Most requiring
489
- * some form of user interaction (click/tap/etc).
490
- * In those cases, audio will be silent until a click/tap triggering one of the following
491
- * - `startAudio`
492
- * - `getUserMedia`
493
- */
494
- startAudio() {
495
- return __awaiter(this, void 0, void 0, function* () {
496
- this.acquireAudioContext();
497
- const elements = [];
498
- this.participants.forEach((p) => {
499
- p.audioTracks.forEach((t) => {
500
- if (t.track) {
501
- t.track.attachedElements.forEach((e) => {
502
- elements.push(e);
503
- });
504
- }
505
- });
506
- });
507
- try {
508
- yield Promise.all(elements.map((e) => e.play()));
509
- this.handleAudioPlaybackStarted();
510
- }
511
- catch (err) {
512
- this.handleAudioPlaybackFailed(err);
513
- throw err;
514
- }
515
- });
516
- }
517
- /**
518
- * Returns true if audio playback is enabled
519
- */
520
- get canPlaybackAudio() {
521
- return this.audioEnabled;
522
- }
523
- /**
524
- * Switches all active device used in this room to the given device.
525
- *
526
- * Note: setting AudioOutput is not supported on some browsers. See [setSinkId](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId#browser_compatibility)
527
- *
528
- * @param kind use `videoinput` for camera track,
529
- * `audioinput` for microphone track,
530
- * `audiooutput` to set speaker for all incoming audio tracks
531
- * @param deviceId
532
- */
533
- switchActiveDevice(kind, deviceId) {
534
- return __awaiter(this, void 0, void 0, function* () {
535
- if (kind === 'audioinput') {
536
- const tracks = Array
537
- .from(this.localParticipant.audioTracks.values())
538
- .filter((track) => track.source === Track_1.Track.Source.Microphone);
539
- yield Promise.all(tracks.map((t) => { var _a; return (_a = t.audioTrack) === null || _a === void 0 ? void 0 : _a.setDeviceId(deviceId); }));
540
- this.options.audioCaptureDefaults.deviceId = deviceId;
541
- }
542
- else if (kind === 'videoinput') {
543
- const tracks = Array
544
- .from(this.localParticipant.videoTracks.values())
545
- .filter((track) => track.source === Track_1.Track.Source.Camera);
546
- yield Promise.all(tracks.map((t) => { var _a; return (_a = t.videoTrack) === null || _a === void 0 ? void 0 : _a.setDeviceId(deviceId); }));
547
- this.options.videoCaptureDefaults.deviceId = deviceId;
548
- }
549
- else if (kind === 'audiooutput') {
550
- const elements = [];
551
- this.participants.forEach((p) => {
552
- p.audioTracks.forEach((t) => {
553
- if (t.isSubscribed && t.track) {
554
- t.track.attachedElements.forEach((e) => {
555
- elements.push(e);
556
- });
557
- }
558
- });
559
- });
560
- yield Promise.all(elements.map((e) => __awaiter(this, void 0, void 0, function* () {
561
- if ('setSinkId' in e) {
562
- /* @ts-ignore */
563
- yield e.setSinkId(deviceId);
564
- }
565
- })));
566
- }
567
- });
568
- }
569
- onTrackAdded(mediaTrack, stream, receiver) {
570
- const parts = utils_2.unpackStreamId(stream.id);
571
- const participantId = parts[0];
572
- let trackId = parts[1];
573
- if (!trackId || trackId === '')
574
- trackId = mediaTrack.id;
575
- const participant = this.getOrCreateParticipant(participantId);
576
- let adaptiveStreamSettings;
577
- if (this.options.adaptiveStream) {
578
- if (typeof this.options.adaptiveStream === 'object') {
579
- adaptiveStreamSettings = this.options.adaptiveStream;
580
- }
581
- else {
582
- adaptiveStreamSettings = {};
583
- }
584
- }
585
- participant.addSubscribedMediaTrack(mediaTrack, trackId, stream, receiver, adaptiveStreamSettings);
586
- }
587
- handleDisconnect(shouldStopTracks = true) {
588
- if (this.state === RoomState.Disconnected) {
589
- return;
590
- }
591
- this.participants.forEach((p) => {
592
- p.tracks.forEach((pub) => {
593
- p.unpublishTrack(pub.trackSid);
594
- });
595
- });
596
- this.localParticipant.tracks.forEach((pub) => {
597
- var _a, _b;
598
- if (pub.track) {
599
- this.localParticipant.unpublishTrack(pub.track);
600
- }
601
- if (shouldStopTracks) {
602
- (_a = pub.track) === null || _a === void 0 ? void 0 : _a.detach();
603
- (_b = pub.track) === null || _b === void 0 ? void 0 : _b.stop();
604
- }
605
- });
606
- this.participants.clear();
607
- this.activeSpeakers = [];
608
- if (this.audioContext) {
609
- this.audioContext.close();
610
- this.audioContext = undefined;
611
- }
612
- if (utils_2.isWeb()) {
613
- window.removeEventListener('beforeunload', this.onBeforeUnload);
614
- navigator.mediaDevices.removeEventListener('devicechange', this.handleDeviceChange);
615
- }
616
- this.state = RoomState.Disconnected;
617
- this.emit(events_2.RoomEvent.Disconnected);
618
- this.emit(events_2.RoomEvent.StateChanged, this.state);
619
- }
620
- handleParticipantDisconnected(sid, participant) {
621
- // remove and send event
622
- this.participants.delete(sid);
623
- if (!participant) {
624
- return;
625
- }
626
- participant.tracks.forEach((publication) => {
627
- participant.unpublishTrack(publication.trackSid);
628
- });
629
- this.emit(events_2.RoomEvent.ParticipantDisconnected, participant);
630
- }
631
- acquireAudioContext() {
632
- if (this.audioContext) {
633
- this.audioContext.close();
634
- }
635
- // by using an AudioContext, it reduces lag on audio elements
636
- // https://stackoverflow.com/questions/9811429/html5-audio-tag-on-safari-has-a-delay/54119854#54119854
637
- const ctx = utils_1.getNewAudioContext();
638
- if (ctx) {
639
- this.audioContext = ctx;
640
- }
641
- }
642
- createParticipant(id, info) {
643
- let participant;
644
- if (info) {
645
- participant = RemoteParticipant_1.default.fromParticipantInfo(this.engine.client, info);
646
- }
647
- else {
648
- participant = new RemoteParticipant_1.default(this.engine.client, id, '');
649
- }
650
- return participant;
651
- }
652
- getOrCreateParticipant(id, info) {
653
- if (this.participants.has(id)) {
654
- return this.participants.get(id);
655
- }
656
- // it's possible for the RTC track to arrive before signaling data
657
- // when this happens, we'll create the participant and make the track work
658
- const participant = this.createParticipant(id, info);
659
- this.participants.set(id, participant);
660
- // also forward events
661
- // trackPublished is only fired for tracks added after both local participant
662
- // and remote participant joined the room
663
- participant
664
- .on(events_2.ParticipantEvent.TrackPublished, (trackPublication) => {
665
- this.emit(events_2.RoomEvent.TrackPublished, trackPublication, participant);
666
- })
667
- .on(events_2.ParticipantEvent.TrackSubscribed, (track, publication) => {
668
- // monitor playback status
669
- if (track.kind === Track_1.Track.Kind.Audio) {
670
- track.on(events_2.TrackEvent.AudioPlaybackStarted, this.handleAudioPlaybackStarted);
671
- track.on(events_2.TrackEvent.AudioPlaybackFailed, this.handleAudioPlaybackFailed);
672
- }
673
- this.emit(events_2.RoomEvent.TrackSubscribed, track, publication, participant);
674
- })
675
- .on(events_2.ParticipantEvent.TrackUnpublished, (publication) => {
676
- this.emit(events_2.RoomEvent.TrackUnpublished, publication, participant);
677
- })
678
- .on(events_2.ParticipantEvent.TrackUnsubscribed, (track, publication) => {
679
- this.emit(events_2.RoomEvent.TrackUnsubscribed, track, publication, participant);
680
- })
681
- .on(events_2.ParticipantEvent.TrackSubscriptionFailed, (sid) => {
682
- this.emit(events_2.RoomEvent.TrackSubscriptionFailed, sid, participant);
683
- })
684
- .on(events_2.ParticipantEvent.TrackMuted, (pub) => {
685
- this.emit(events_2.RoomEvent.TrackMuted, pub, participant);
686
- })
687
- .on(events_2.ParticipantEvent.TrackUnmuted, (pub) => {
688
- this.emit(events_2.RoomEvent.TrackUnmuted, pub, participant);
689
- })
690
- .on(events_2.ParticipantEvent.MetadataChanged, (metadata) => {
691
- this.emit(events_2.RoomEvent.MetadataChanged, metadata, participant);
692
- })
693
- .on(events_2.ParticipantEvent.ParticipantMetadataChanged, (metadata) => {
694
- this.emit(events_2.RoomEvent.ParticipantMetadataChanged, metadata, participant);
695
- })
696
- .on(events_2.ParticipantEvent.ConnectionQualityChanged, (quality) => {
697
- this.emit(events_2.RoomEvent.ConnectionQualityChanged, quality, participant);
698
- })
699
- .on(events_2.ParticipantEvent.ParticipantPermissionsChanged, (prevPermissions) => {
700
- this.emit(events_2.RoomEvent.ParticipantPermissionsChanged, prevPermissions, participant);
701
- });
702
- return participant;
703
- }
704
- sendSyncState() {
705
- var _a;
706
- if (this.engine.subscriber === undefined
707
- || this.engine.subscriber.pc.localDescription === null) {
708
- return;
709
- }
710
- const previousSdp = this.engine.subscriber.pc.localDescription;
711
- /* 1. autosubscribe on, so subscribed tracks = all tracks - unsub tracks,
712
- in this case, we send unsub tracks, so server add all tracks to this
713
- subscribe pc and unsub special tracks from it.
714
- 2. autosubscribe off, we send subscribed tracks.
715
- */
716
- const sendUnsub = ((_a = this.connOptions) === null || _a === void 0 ? void 0 : _a.autoSubscribe) || false;
717
- const trackSids = new Array();
718
- this.participants.forEach((participant) => {
719
- participant.tracks.forEach((track) => {
720
- if (track.isSubscribed !== sendUnsub) {
721
- trackSids.push(track.trackSid);
722
- }
723
- });
724
- });
725
- this.engine.client.sendSyncState({
726
- answer: SignalClient_1.toProtoSessionDescription({
727
- sdp: previousSdp.sdp,
728
- type: previousSdp.type,
729
- }),
730
- subscription: {
731
- trackSids,
732
- subscribe: !sendUnsub,
733
- participantTracks: [],
734
- },
735
- publishTracks: this.localParticipant.publishedTracksInfo(),
736
- dataChannels: this.localParticipant.dataChannelsInfo(),
737
- });
738
- }
739
- /**
740
- * After resuming, we'll need to notify the server of the current
741
- * subscription settings.
742
- */
743
- updateSubscriptions() {
744
- for (const p of this.participants.values()) {
745
- for (const pub of p.videoTracks.values()) {
746
- if (pub.isSubscribed && pub instanceof RemoteTrackPublication_1.default) {
747
- pub.emitTrackUpdate();
748
- }
749
- }
750
- }
751
- }
752
- // /** @internal */
753
- emit(event, ...args) {
754
- logger_1.default.debug('room event', event, ...args);
755
- return super.emit(event, ...args);
756
- }
757
- }
758
- exports.default = Room;
759
- //# sourceMappingURL=Room.js.map