livekit-client 0.12.2 → 0.13.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 (81) hide show
  1. package/.eslintrc.js +1 -0
  2. package/.github/workflows/publish.yaml +1 -3
  3. package/dist/api/SignalClient.d.ts +3 -1
  4. package/dist/api/SignalClient.js +8 -0
  5. package/dist/api/SignalClient.js.map +1 -1
  6. package/dist/connect.d.ts +23 -0
  7. package/dist/connect.js +93 -0
  8. package/dist/connect.js.map +1 -0
  9. package/dist/index.d.ts +2 -1
  10. package/dist/index.js +2 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/options.d.ts +5 -3
  13. package/dist/options.js.map +1 -1
  14. package/dist/proto/livekit_models.d.ts +15 -0
  15. package/dist/proto/livekit_models.js +129 -1
  16. package/dist/proto/livekit_models.js.map +1 -1
  17. package/dist/proto/livekit_rtc.d.ts +16 -1
  18. package/dist/proto/livekit_rtc.js +116 -1
  19. package/dist/proto/livekit_rtc.js.map +1 -1
  20. package/dist/room/DeviceManager.d.ts +10 -0
  21. package/dist/room/DeviceManager.js +77 -0
  22. package/dist/room/DeviceManager.js.map +1 -0
  23. package/dist/room/RTCEngine.d.ts +1 -1
  24. package/dist/room/RTCEngine.js +8 -7
  25. package/dist/room/RTCEngine.js.map +1 -1
  26. package/dist/room/Room.d.ts +45 -2
  27. package/dist/room/Room.js +108 -2
  28. package/dist/room/Room.js.map +1 -1
  29. package/dist/room/defaults.d.ts +3 -0
  30. package/dist/room/defaults.js +13 -0
  31. package/dist/room/defaults.js.map +1 -0
  32. package/dist/room/events.d.ts +23 -2
  33. package/dist/room/events.js +22 -1
  34. package/dist/room/events.js.map +1 -1
  35. package/dist/room/participant/LocalParticipant.d.ts +28 -0
  36. package/dist/room/participant/LocalParticipant.js +127 -13
  37. package/dist/room/participant/LocalParticipant.js.map +1 -1
  38. package/dist/room/participant/Participant.d.ts +14 -0
  39. package/dist/room/participant/Participant.js +39 -0
  40. package/dist/room/participant/Participant.js.map +1 -1
  41. package/dist/room/participant/RemoteParticipant.d.ts +2 -0
  42. package/dist/room/participant/RemoteParticipant.js +14 -0
  43. package/dist/room/participant/RemoteParticipant.js.map +1 -1
  44. package/dist/room/track/LocalAudioTrack.d.ts +3 -0
  45. package/dist/room/track/LocalAudioTrack.js +37 -0
  46. package/dist/room/track/LocalAudioTrack.js.map +1 -1
  47. package/dist/room/track/LocalTrack.d.ts +6 -2
  48. package/dist/room/track/LocalTrack.js +34 -5
  49. package/dist/room/track/LocalTrack.js.map +1 -1
  50. package/dist/room/track/LocalTrackPublication.d.ts +6 -3
  51. package/dist/room/track/LocalTrackPublication.js +21 -2
  52. package/dist/room/track/LocalTrackPublication.js.map +1 -1
  53. package/dist/room/track/LocalVideoTrack.d.ts +3 -2
  54. package/dist/room/track/LocalVideoTrack.js +34 -5
  55. package/dist/room/track/LocalVideoTrack.js.map +1 -1
  56. package/dist/room/track/RemoteAudioTrack.d.ts +2 -0
  57. package/dist/room/track/RemoteAudioTrack.js +8 -0
  58. package/dist/room/track/RemoteAudioTrack.js.map +1 -1
  59. package/dist/room/track/RemoteVideoTrack.d.ts +1 -0
  60. package/dist/room/track/RemoteVideoTrack.js +6 -1
  61. package/dist/room/track/RemoteVideoTrack.js.map +1 -1
  62. package/dist/room/track/Track.d.ts +14 -2
  63. package/dist/room/track/Track.js +42 -0
  64. package/dist/room/track/Track.js.map +1 -1
  65. package/dist/room/track/TrackPublication.d.ts +1 -0
  66. package/dist/room/track/TrackPublication.js +2 -0
  67. package/dist/room/track/TrackPublication.js.map +1 -1
  68. package/dist/room/track/create.d.ts +23 -0
  69. package/dist/{livekit.js → room/track/create.js} +72 -109
  70. package/dist/room/track/create.js.map +1 -0
  71. package/dist/room/track/options.d.ts +42 -17
  72. package/dist/room/track/options.js +11 -6
  73. package/dist/room/track/options.js.map +1 -1
  74. package/dist/version.d.ts +2 -2
  75. package/dist/version.js +2 -2
  76. package/example/index.html +51 -20
  77. package/example/sample.ts +195 -79
  78. package/example/webpack.config.js +8 -2
  79. package/package.json +2 -2
  80. package/dist/livekit.d.ts +0 -44
  81. package/dist/livekit.js.map +0 -1
package/example/sample.ts CHANGED
@@ -1,8 +1,5 @@
1
1
  import {
2
- connect, createLocalScreenTracks, CreateVideoTrackOptions, DataPacket_Kind, LocalAudioTrack,
3
- LocalTrack,
4
- LocalVideoTrack,
5
- LogLevel,
2
+ connect, CreateVideoTrackOptions, DataPacket_Kind, LocalTrack, LogLevel,
6
3
  Participant,
7
4
  ParticipantEvent,
8
5
  RemoteParticipant,
@@ -18,9 +15,10 @@ declare global {
18
15
  interface Window {
19
16
  connectWithFormInput: any;
20
17
  connectToRoom: any;
18
+ handleDeviceSelected: any;
21
19
  shareScreen: any;
22
- muteVideo: any;
23
- muteAudio: any;
20
+ toggleVideo: any;
21
+ toggleAudio: any;
24
22
  enterText: any;
25
23
  disconnectSignal: any;
26
24
  disconnectRoom: any;
@@ -142,21 +140,42 @@ function participantDisconnected(participant: RemoteParticipant) {
142
140
  function handleRoomDisconnect() {
143
141
  appendLog('disconnected from room');
144
142
  setButtonsForState(false);
145
- if (videoTrack) {
146
- videoTrack.stop();
147
- trackUnsubscribed(videoTrack);
143
+ $('local-video')!.innerHTML = '';
144
+
145
+ // clear the chat area on disconnect
146
+ clearChat();
147
+
148
+ // clear remote area on disconnect
149
+ clearRemoteArea();
150
+ }
151
+
152
+ function setButtonState(buttonId: string, buttonText: string, isActive: boolean) {
153
+ const el = $(buttonId);
154
+ if (!el) return;
155
+
156
+ el.innerHTML = buttonText;
157
+ if (isActive) {
158
+ el.classList.add('active');
159
+ } else {
160
+ el.classList.remove('active');
148
161
  }
149
- if (audioTrack) {
150
- audioTrack.stop();
151
- trackUnsubscribed(audioTrack);
162
+ }
163
+
164
+ function clearChat() {
165
+ const chat = <HTMLTextAreaElement>$('chat');
166
+ chat.value = '';
167
+ }
168
+
169
+ function clearRemoteArea() {
170
+ const el = $('remote-area');
171
+ if (!el) return;
172
+
173
+ while (el.firstChild) {
174
+ el.removeChild(el.firstChild);
152
175
  }
153
- $('local-video')!.innerHTML = '';
154
176
  }
155
177
 
156
178
  let currentRoom: Room;
157
- let videoTrack: LocalVideoTrack | undefined;
158
- let audioTrack: LocalAudioTrack;
159
- let screenTrack: LocalVideoTrack | undefined;
160
179
  window.connectWithFormInput = () => {
161
180
  const url = (<HTMLInputElement>$('url')).value;
162
181
  const token = (<HTMLInputElement>$('token')).value;
@@ -177,13 +196,21 @@ window.connectToRoom = async (
177
196
  if (forceTURN) {
178
197
  rtcConfig.iceTransportPolicy = 'relay';
179
198
  }
199
+ const shouldPublish = (<HTMLInputElement>$('publish-option')).checked;
200
+ let audioOptions = true;
201
+ let videoOptions: boolean | CreateVideoTrackOptions = {
202
+ resolution: VideoPresets.qhd.resolution,
203
+ };
204
+ if (!shouldPublish) {
205
+ audioOptions = false;
206
+ videoOptions = false;
207
+ }
208
+
180
209
  try {
181
210
  room = await connect(url, token, {
182
211
  logLevel: LogLevel.debug,
183
- audio: true,
184
- video: {
185
- resolution: VideoPresets.qhd.resolution,
186
- },
212
+ audio: audioOptions,
213
+ video: videoOptions,
187
214
  simulcast,
188
215
  rtcConfig,
189
216
  });
@@ -196,11 +223,11 @@ window.connectToRoom = async (
196
223
  return;
197
224
  }
198
225
 
199
- window.currentRoom = room;
200
226
  appendLog('connected to room', room.name);
201
- setButtonsForState(true);
202
227
  currentRoom = room;
203
228
  window.currentRoom = room;
229
+ setButtonsForState(true);
230
+ updateButtonsForPublishState();
204
231
 
205
232
  room
206
233
  .on(RoomEvent.ParticipantConnected, participantConnected)
@@ -212,6 +239,10 @@ window.connectToRoom = async (
212
239
  .on(RoomEvent.Reconnected, () => appendLog('Successfully reconnected!'))
213
240
  .on(RoomEvent.TrackMuted, (pub: TrackPublication, p: Participant) => appendLog('track was muted', pub.trackSid, p.identity))
214
241
  .on(RoomEvent.TrackUnmuted, (pub: TrackPublication, p: Participant) => appendLog('track was unmuted', pub.trackSid, p.identity))
242
+ .on(RoomEvent.RoomMetadataChanged, (metadata) => {
243
+ appendLog('new metadata for room', metadata);
244
+ })
245
+ .on(RoomEvent.MediaDevicesChanged, handleDevicesChanged)
215
246
  .on(RoomEvent.AudioPlaybackStatusChanged, () => {
216
247
  if (room.canPlaybackAudio) {
217
248
  $('start-audio-button')?.setAttribute('disabled', 'true');
@@ -226,48 +257,40 @@ window.connectToRoom = async (
226
257
  });
227
258
 
228
259
  $('local-video')!.innerHTML = `${room.localParticipant.identity} (me)`;
229
-
230
- // add already published tracks
231
- currentRoom.localParticipant.tracks.forEach((publication) => {
232
- if (publication.kind === Track.Kind.Video) {
233
- videoTrack = <LocalVideoTrack>publication.track;
234
- publishLocalVideo(videoTrack);
235
- } else if (publication.kind === Track.Kind.Audio) {
236
- // skip adding local audio track, to avoid your own sound
237
- // only process local video tracks
238
- audioTrack = <LocalAudioTrack>publication.track;
239
- }
240
- });
260
+ attachLocalVideo();
241
261
  };
242
262
 
243
- window.muteVideo = () => {
244
- if (!currentRoom || !videoTrack) return;
263
+ window.toggleVideo = async () => {
264
+ if (!currentRoom) return;
245
265
  const video = getMyVideo();
246
- if (!videoTrack.isMuted) {
247
- appendLog('muting video');
248
- videoTrack.mute();
266
+ if (currentRoom.localParticipant.isCameraEnabled) {
267
+ appendLog('disabling video');
268
+ await currentRoom.localParticipant.setCameraEnabled(false);
249
269
  // hide from display
250
270
  if (video) {
251
271
  video.style.display = 'none';
252
272
  }
253
273
  } else {
254
- appendLog('unmuting video');
255
- videoTrack.unmute();
274
+ appendLog('enabling video');
275
+ await currentRoom.localParticipant.setCameraEnabled(true);
276
+ attachLocalVideo();
256
277
  if (video) {
257
278
  video.style.display = '';
258
279
  }
259
280
  }
281
+ updateButtonsForPublishState();
260
282
  };
261
283
 
262
- window.muteAudio = () => {
263
- if (!currentRoom || !audioTrack) return;
264
- if (!audioTrack.isMuted) {
265
- appendLog('muting audio');
266
- audioTrack.mute();
284
+ window.toggleAudio = async () => {
285
+ if (!currentRoom) return;
286
+ if (currentRoom.localParticipant.isMicrophoneEnabled) {
287
+ appendLog('disabling audio');
288
+ await currentRoom.localParticipant.setMicrophoneEnabled(false);
267
289
  } else {
268
- appendLog('unmuting audio');
269
- audioTrack.unmute();
290
+ appendLog('enabling audio');
291
+ await currentRoom.localParticipant.setMicrophoneEnabled(true);
270
292
  }
293
+ updateButtonsForPublishState();
271
294
  };
272
295
 
273
296
  window.enterText = () => {
@@ -283,26 +306,17 @@ window.enterText = () => {
283
306
  };
284
307
 
285
308
  window.shareScreen = async () => {
286
- if (screenTrack !== undefined) {
287
- currentRoom.localParticipant.unpublishTrack(screenTrack);
288
- screenTrack = undefined;
289
- return;
290
- }
309
+ if (!currentRoom) return;
291
310
 
292
- const screenTracks = await createLocalScreenTracks({
293
- audio: true,
294
- });
295
- screenTracks.forEach((track) => {
296
- if (track instanceof LocalVideoTrack) {
297
- screenTrack = track;
298
- currentRoom.localParticipant.publishTrack(track, {
299
- videoEncoding: VideoPresets.fhd.encoding,
300
- });
301
- } else {
302
- // publish audio track as well
303
- currentRoom.localParticipant.publishTrack(track);
304
- }
305
- });
311
+ if (currentRoom.localParticipant.isScreenShareEnabled) {
312
+ appendLog('stopping screen share');
313
+ await currentRoom.localParticipant.setScreenShareEnabled(false);
314
+ } else {
315
+ appendLog('starting screen share');
316
+ await currentRoom.localParticipant.setScreenShareEnabled(true);
317
+ appendLog('started screen share');
318
+ }
319
+ updateButtonsForPublishState();
306
320
  };
307
321
 
308
322
  window.disconnectSignal = () => {
@@ -323,31 +337,59 @@ window.startAudio = () => {
323
337
  currentRoom.startAudio();
324
338
  };
325
339
 
326
- let isFacingForward = true;
340
+ let isFrontFacing = true;
327
341
  window.flipVideo = () => {
328
- if (!videoTrack) {
342
+ const videoPub = currentRoom.localParticipant.getTrack(Track.Source.Camera);
343
+ if (!videoPub) {
329
344
  return;
330
345
  }
331
- isFacingForward = !isFacingForward;
346
+ if (isFrontFacing) {
347
+ setButtonState('flip-video-button', 'Front Camera', false);
348
+ } else {
349
+ setButtonState('flip-video-button', 'Back Camera', false);
350
+ }
351
+ isFrontFacing = !isFrontFacing;
332
352
  const options: CreateVideoTrackOptions = {
333
353
  resolution: VideoPresets.qhd.resolution,
334
- facingMode: isFacingForward ? 'user' : 'environment',
354
+ facingMode: isFrontFacing ? 'user' : 'environment',
335
355
  };
336
- videoTrack.restartTrack(options);
356
+ videoPub.videoTrack?.restartTrack(options);
357
+ };
358
+
359
+ window.handleDeviceSelected = async (e: Event) => {
360
+ const deviceId = (<HTMLSelectElement>e.target).value;
361
+ const elementId = (<HTMLSelectElement>e.target).id;
362
+ const kind = elementMapping[elementId];
363
+ if (!kind) {
364
+ return;
365
+ }
366
+
367
+ Room.setDefaultDevice(kind, deviceId || undefined);
368
+ if (currentRoom) {
369
+ await currentRoom.switchActiveDevice(kind, deviceId);
370
+ }
337
371
  };
338
372
 
339
- async function publishLocalVideo(track: LocalVideoTrack) {
340
- await currentRoom.localParticipant.publishTrack(track);
341
- const video = track.attach();
342
- video.style.transform = 'scale(-1, 1)';
343
- $('local-video')!.appendChild(video);
373
+ setTimeout(handleDevicesChanged, 100);
374
+
375
+ async function attachLocalVideo() {
376
+ const videoPub = currentRoom.localParticipant.getTrack(Track.Source.Camera);
377
+ const videoTrack = videoPub?.videoTrack;
378
+ if (!videoTrack) {
379
+ return;
380
+ }
381
+
382
+ if (videoTrack.attachedElements.length === 0) {
383
+ const video = videoTrack.attach();
384
+ video.style.transform = 'scale(-1, 1)';
385
+ $('local-video')!.appendChild(video);
386
+ }
344
387
  }
345
388
 
346
389
  function setButtonsForState(connected: boolean) {
347
390
  const connectedSet = [
348
391
  'toggle-video-button',
349
- 'mute-video-button',
350
- 'mute-audio-button',
392
+ 'toggle-audio-button',
351
393
  'share-screen-button',
352
394
  'disconnect-ws-button',
353
395
  'disconnect-room-button',
@@ -365,3 +407,77 @@ function setButtonsForState(connected: boolean) {
365
407
  function getMyVideo() {
366
408
  return <HTMLVideoElement>document.querySelector('#local-video video');
367
409
  }
410
+
411
+ const elementMapping: { [k: string]: MediaDeviceKind } = {
412
+ 'video-input': 'videoinput',
413
+ 'audio-input': 'audioinput',
414
+ 'audio-output': 'audiooutput',
415
+ };
416
+ async function handleDevicesChanged() {
417
+ Promise.all(Object.keys(elementMapping).map(async (id) => {
418
+ const kind = elementMapping[id];
419
+ if (!kind) {
420
+ return;
421
+ }
422
+ const devices = await Room.getLocalDevices(kind);
423
+ const element = <HTMLSelectElement>$(id);
424
+ populateSelect(kind, element, devices, Room.getDefaultDevice(kind));
425
+ }));
426
+ }
427
+
428
+ function populateSelect(
429
+ kind: MediaDeviceKind,
430
+ element: HTMLSelectElement,
431
+ devices: MediaDeviceInfo[],
432
+ selectedDeviceId?: string,
433
+ ) {
434
+ // clear all elements
435
+ element.innerHTML = '';
436
+ const initialOption = document.createElement('option');
437
+ if (kind === 'audioinput') {
438
+ initialOption.text = 'Audio Input (default)';
439
+ } else if (kind === 'videoinput') {
440
+ initialOption.text = 'Video Input (default)';
441
+ } else if (kind === 'audiooutput') {
442
+ initialOption.text = 'Audio Output (default)';
443
+ }
444
+ element.appendChild(initialOption);
445
+
446
+ for (const device of devices) {
447
+ const option = document.createElement('option');
448
+ option.text = device.label;
449
+ option.value = device.deviceId;
450
+ if (device.deviceId === selectedDeviceId) {
451
+ option.selected = true;
452
+ }
453
+ element.appendChild(option);
454
+ }
455
+ }
456
+
457
+ function updateButtonsForPublishState() {
458
+ if (!currentRoom) {
459
+ return;
460
+ }
461
+ const lp = currentRoom.localParticipant;
462
+
463
+ // video
464
+ setButtonState(
465
+ 'toggle-video-button',
466
+ `${lp.isCameraEnabled ? 'Disable' : 'Enable'} Video`,
467
+ lp.isCameraEnabled,
468
+ );
469
+
470
+ // audio
471
+ setButtonState(
472
+ 'toggle-audio-button',
473
+ `${lp.isMicrophoneEnabled ? 'Disable' : 'Enable'} Audio`,
474
+ lp.isMicrophoneEnabled,
475
+ );
476
+
477
+ // screen share
478
+ setButtonState(
479
+ 'share-screen-button',
480
+ lp.isScreenShareEnabled ? 'Stop Screen Share' : 'Share Screen',
481
+ lp.isScreenShareEnabled,
482
+ );
483
+ }
@@ -5,8 +5,14 @@ module.exports = {
5
5
  mode: 'development',
6
6
  devtool: 'inline-source-map',
7
7
  devServer: {
8
- open: true,
9
- contentBase: __dirname,
8
+ host: '0.0.0.0',
9
+ open: {
10
+ target: 'http://localhost:8080/',
11
+ },
12
+ port: 8080,
13
+ static: {
14
+ directory: __dirname,
15
+ },
10
16
  },
11
17
  module: {
12
18
  rules: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livekit-client",
3
- "version": "0.12.2",
3
+ "version": "0.13.0",
4
4
  "description": "JavaScript/TypeScript client SDK for LiveKit",
5
5
  "main": "dist/index.js",
6
6
  "source": "src/index.ts",
@@ -12,7 +12,7 @@
12
12
  "build": "yarn exec tsc",
13
13
  "build-docs": "yarn exec typedoc",
14
14
  "proto": "protoc --plugin=node_modules/ts-proto/protoc-gen-ts_proto --ts_proto_opt=esModuleInterop=true --ts_proto_out=./src/proto --ts_proto_opt=outputClientImpl=false,useOptionals=true -I../protocol ../protocol/livekit_rtc.proto ../protocol/livekit_models.proto",
15
- "sample": "cd example && webpack serve --host 0.0.0.0 --public localhost:8080",
15
+ "sample": "cd example && webpack serve",
16
16
  "build-sample": "cd example && webpack && cp index.html dist/",
17
17
  "lint": "yarn exec eslint src",
18
18
  "test": "jest",
package/dist/livekit.d.ts DELETED
@@ -1,44 +0,0 @@
1
- import { ConnectOptions } from './options';
2
- import Room from './room/Room';
3
- import LocalAudioTrack from './room/track/LocalAudioTrack';
4
- import LocalTrack from './room/track/LocalTrack';
5
- import LocalVideoTrack from './room/track/LocalVideoTrack';
6
- import { CreateAudioTrackOptions, CreateLocalTracksOptions, CreateScreenTrackOptions, CreateVideoTrackOptions } from './room/track/options';
7
- export { version } from './version';
8
- /**
9
- * Connects to a LiveKit room
10
- *
11
- * ```typescript
12
- * connect('wss://myhost.livekit.io', token, {
13
- * // publish audio and video tracks on joining
14
- * audio: true,
15
- * video: {
16
- * resolution: VideoPresets.hd,
17
- * facingMode: {
18
- * ideal: "user",
19
- * }
20
- * }
21
- * })
22
- * ```
23
- * @param url URL to LiveKit server
24
- * @param token AccessToken, a JWT token that includes authentication and room details
25
- * @param options
26
- */
27
- export declare function connect(url: string, token: string, options?: ConnectOptions): Promise<Room>;
28
- /**
29
- * Creates a [[LocalVideoTrack]] with getUserMedia()
30
- * @param options
31
- */
32
- export declare function createLocalVideoTrack(options?: CreateVideoTrackOptions): Promise<LocalVideoTrack>;
33
- export declare function createLocalAudioTrack(options?: CreateAudioTrackOptions): Promise<LocalAudioTrack>;
34
- /**
35
- * Creates a screen capture tracks with getDisplayMedia().
36
- * A LocalVideoTrack is always created and returned.
37
- * If { audio: true }, and the browser supports audio capture, a LocalAudioTrack is also created.
38
- */
39
- export declare function createLocalScreenTracks(options?: CreateScreenTrackOptions): Promise<Array<LocalTrack>>;
40
- /**
41
- * creates a local video and audio track at the same time
42
- * @param options
43
- */
44
- export declare function createLocalTracks(options?: CreateLocalTracksOptions): Promise<Array<LocalTrack>>;
@@ -1 +0,0 @@
1
- {"version":3,"file":"livekit.js","sourceRoot":"","sources":["../src/livekit.ts"],"names":[],"mappings":"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"}