livekit-client 2.1.1 → 2.1.2

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 (45) hide show
  1. package/dist/livekit-client.esm.mjs +159 -7
  2. package/dist/livekit-client.esm.mjs.map +1 -1
  3. package/dist/livekit-client.umd.js +1 -1
  4. package/dist/livekit-client.umd.js.map +1 -1
  5. package/dist/src/index.d.ts +1 -1
  6. package/dist/src/index.d.ts.map +1 -1
  7. package/dist/src/room/RTCEngine.d.ts +2 -1
  8. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  9. package/dist/src/room/Room.d.ts +5 -2
  10. package/dist/src/room/Room.d.ts.map +1 -1
  11. package/dist/src/room/events.d.ts +20 -1
  12. package/dist/src/room/events.d.ts.map +1 -1
  13. package/dist/src/room/participant/Participant.d.ts +2 -1
  14. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  15. package/dist/src/room/track/RemoteTrack.d.ts +1 -0
  16. package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
  17. package/dist/src/room/track/Track.d.ts +4 -0
  18. package/dist/src/room/track/Track.d.ts.map +1 -1
  19. package/dist/src/room/track/TrackPublication.d.ts +3 -1
  20. package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
  21. package/dist/src/room/types.d.ts +8 -0
  22. package/dist/src/room/types.d.ts.map +1 -1
  23. package/dist/src/room/utils.d.ts +3 -1
  24. package/dist/src/room/utils.d.ts.map +1 -1
  25. package/dist/ts4.2/src/index.d.ts +1 -1
  26. package/dist/ts4.2/src/room/RTCEngine.d.ts +2 -1
  27. package/dist/ts4.2/src/room/Room.d.ts +5 -2
  28. package/dist/ts4.2/src/room/events.d.ts +20 -1
  29. package/dist/ts4.2/src/room/participant/Participant.d.ts +2 -1
  30. package/dist/ts4.2/src/room/track/RemoteTrack.d.ts +1 -0
  31. package/dist/ts4.2/src/room/track/Track.d.ts +4 -0
  32. package/dist/ts4.2/src/room/track/TrackPublication.d.ts +3 -1
  33. package/dist/ts4.2/src/room/types.d.ts +8 -0
  34. package/dist/ts4.2/src/room/utils.d.ts +3 -1
  35. package/package.json +8 -8
  36. package/src/index.ts +1 -1
  37. package/src/room/RTCEngine.ts +4 -0
  38. package/src/room/Room.ts +27 -1
  39. package/src/room/events.ts +23 -0
  40. package/src/room/participant/Participant.ts +5 -1
  41. package/src/room/track/RemoteTrack.ts +13 -0
  42. package/src/room/track/Track.ts +9 -0
  43. package/src/room/track/TrackPublication.ts +3 -1
  44. package/src/room/types.ts +9 -0
  45. package/src/room/utils.ts +17 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livekit-client",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "JavaScript/TypeScript client SDK for LiveKit",
5
5
  "main": "./dist/livekit-client.umd.js",
6
6
  "unpkg": "./dist/livekit-client.umd.js",
@@ -36,7 +36,7 @@
36
36
  "author": "David Zhao <david@davidzhao.com>",
37
37
  "license": "Apache-2.0",
38
38
  "dependencies": {
39
- "@livekit/protocol": "1.13.0",
39
+ "@livekit/protocol": "1.15.0",
40
40
  "events": "^3.3.0",
41
41
  "loglevel": "^1.8.0",
42
42
  "sdp-transform": "^2.14.1",
@@ -46,8 +46,8 @@
46
46
  "webrtc-adapter": "^8.1.1"
47
47
  },
48
48
  "devDependencies": {
49
- "@babel/core": "7.24.4",
50
- "@babel/preset-env": "7.24.4",
49
+ "@babel/core": "7.24.5",
50
+ "@babel/preset-env": "7.24.5",
51
51
  "@bufbuild/protoc-gen-es": "^1.3.0",
52
52
  "@changesets/cli": "2.27.1",
53
53
  "@livekit/changesets-changelog-github": "^0.0.4",
@@ -73,15 +73,15 @@
73
73
  "gh-pages": "6.1.1",
74
74
  "jsdom": "^24.0.0",
75
75
  "prettier": "^3.0.0",
76
- "rollup": "4.14.0",
76
+ "rollup": "4.17.2",
77
77
  "rollup-plugin-delete": "^2.0.0",
78
78
  "rollup-plugin-re": "1.0.7",
79
79
  "rollup-plugin-typescript2": "0.36.0",
80
80
  "size-limit": "^8.2.4",
81
- "typedoc": "0.25.12",
81
+ "typedoc": "0.25.13",
82
82
  "typedoc-plugin-no-inherit": "1.4.0",
83
- "typescript": "5.4.3",
84
- "vite": "5.0.13",
83
+ "typescript": "5.4.5",
84
+ "vite": "5.2.10",
85
85
  "vitest": "^1.0.0"
86
86
  },
87
87
  "scripts": {
package/src/index.ts CHANGED
@@ -44,7 +44,7 @@ export { facingModeFromDeviceLabel, facingModeFromLocalTrack } from './room/trac
44
44
  export * from './room/track/options';
45
45
  export * from './room/track/processor/types';
46
46
  export * from './room/track/types';
47
- export type { DataPublishOptions, SimulationScenario } from './room/types';
47
+ export type { DataPublishOptions, SimulationScenario, TranscriptionSegment } from './room/types';
48
48
  export * from './version';
49
49
  export {
50
50
  ConnectionQuality,
@@ -23,6 +23,7 @@ import {
23
23
  TrackInfo,
24
24
  type TrackPublishedResponse,
25
25
  TrackUnpublishedResponse,
26
+ Transcription,
26
27
  UpdateSubscription,
27
28
  UserPacket,
28
29
  } from '@livekit/protocol';
@@ -634,6 +635,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
634
635
  this.emit(EngineEvent.ActiveSpeakersUpdate, dp.value.value.speakers);
635
636
  } else if (dp.value?.case === 'user') {
636
637
  this.emit(EngineEvent.DataPacketReceived, dp.value.value, dp.kind);
638
+ } else if (dp.value?.case === 'transcription') {
639
+ this.emit(EngineEvent.TranscriptionReceived, dp.value.value);
637
640
  }
638
641
  } finally {
639
642
  unlock();
@@ -1357,6 +1360,7 @@ export type EngineEventCallbacks = {
1357
1360
  ) => void;
1358
1361
  activeSpeakersUpdate: (speakers: Array<SpeakerInfo>) => void;
1359
1362
  dataPacketReceived: (userPacket: UserPacket, kind: DataPacket_Kind) => void;
1363
+ transcriptionReceived: (transcription: Transcription) => void;
1360
1364
  transportsCreated: (publisher: PCTransport, subscriber: PCTransport) => void;
1361
1365
  /** @internal */
1362
1366
  trackSenderAdded: (track: Track, sender: RTCRtpSender) => void;
package/src/room/Room.ts CHANGED
@@ -18,6 +18,8 @@ import {
18
18
  TrackInfo,
19
19
  TrackSource,
20
20
  TrackType,
21
+ Transcription as TranscriptionModel,
22
+ TranscriptionSegment as TranscriptionSegmentModel,
21
23
  UserPacket,
22
24
  protoInt64,
23
25
  } from '@livekit/protocol';
@@ -61,11 +63,12 @@ import type { TrackPublication } from './track/TrackPublication';
61
63
  import type { TrackProcessor } from './track/processor/types';
62
64
  import type { AdaptiveStreamSettings } from './track/types';
63
65
  import { getNewAudioContext, sourceToKind } from './track/utils';
64
- import type { SimulationOptions, SimulationScenario } from './types';
66
+ import type { SimulationOptions, SimulationScenario, TranscriptionSegment } from './types';
65
67
  import {
66
68
  Future,
67
69
  Mutex,
68
70
  createDummyVideoStreamTrack,
71
+ extractTranscriptionSegments,
69
72
  getEmptyAudioStreamTrack,
70
73
  isBrowserSupported,
71
74
  isCloud,
@@ -330,6 +333,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
330
333
  })
331
334
  .on(EngineEvent.ActiveSpeakersUpdate, this.handleActiveSpeakersUpdate)
332
335
  .on(EngineEvent.DataPacketReceived, this.handleDataPacket)
336
+ .on(EngineEvent.TranscriptionReceived, this.handleTranscription)
333
337
  .on(EngineEvent.Resuming, () => {
334
338
  this.clearConnectionReconcile();
335
339
  this.isResuming = true;
@@ -1471,6 +1475,23 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1471
1475
  participant?.emit(ParticipantEvent.DataReceived, userPacket.payload, kind);
1472
1476
  };
1473
1477
 
1478
+ bufferedSegments: Map<string, TranscriptionSegmentModel> = new Map();
1479
+
1480
+ private handleTranscription = (transcription: TranscriptionModel) => {
1481
+ // find the participant
1482
+ const participant =
1483
+ transcription.participantIdentity === this.localParticipant.identity
1484
+ ? this.localParticipant
1485
+ : this.remoteParticipants.get(transcription.participantIdentity);
1486
+ const publication = participant?.trackPublications.get(transcription.trackId);
1487
+
1488
+ const segments = extractTranscriptionSegments(transcription);
1489
+
1490
+ publication?.emit(TrackEvent.TranscriptionReceived, segments);
1491
+ participant?.emit(ParticipantEvent.TranscriptionReceived, segments, publication);
1492
+ this.emit(RoomEvent.TranscriptionReceived, segments, participant, publication);
1493
+ };
1494
+
1474
1495
  private handleAudioPlaybackStarted = () => {
1475
1496
  if (this.canPlaybackAudio) {
1476
1497
  return;
@@ -2071,6 +2092,11 @@ export type RoomEventCallbacks = {
2071
2092
  kind?: DataPacket_Kind,
2072
2093
  topic?: string,
2073
2094
  ) => void;
2095
+ transcriptionReceived: (
2096
+ transcription: TranscriptionSegment[],
2097
+ participant?: Participant,
2098
+ publication?: TrackPublication,
2099
+ ) => void;
2074
2100
  connectionQualityChanged: (quality: ConnectionQuality, participant: Participant) => void;
2075
2101
  mediaDevicesError: (error: Error) => void;
2076
2102
  trackStreamStateChanged: (
@@ -197,6 +197,12 @@ export enum RoomEvent {
197
197
  */
198
198
  DataReceived = 'dataReceived',
199
199
 
200
+ /**
201
+ * Transcription received from a participant's track.
202
+ * @beta
203
+ */
204
+ TranscriptionReceived = 'transcriptionReceived',
205
+
200
206
  /**
201
207
  * Connection quality was changed for a Participant. It'll receive updates
202
208
  * from the local participant, as well as any [[RemoteParticipant]]s that we are
@@ -402,6 +408,12 @@ export enum ParticipantEvent {
402
408
  */
403
409
  DataReceived = 'dataReceived',
404
410
 
411
+ /**
412
+ * Transcription received from this participant as data source.
413
+ * @beta
414
+ */
415
+ TranscriptionReceived = 'transcriptionReceived',
416
+
405
417
  /**
406
418
  * Has speaking status changed for the current participant
407
419
  *
@@ -479,6 +491,7 @@ export enum EngineEvent {
479
491
  MediaTrackAdded = 'mediaTrackAdded',
480
492
  ActiveSpeakersUpdate = 'activeSpeakersUpdate',
481
493
  DataPacketReceived = 'dataPacketReceived',
494
+ TranscriptionReceived = 'transcriptionReceived',
482
495
  RTPVideoMapUpdate = 'rtpVideoMapUpdate',
483
496
  DCBufferStatusChanged = 'dcBufferStatusChanged',
484
497
  ParticipantUpdate = 'participantUpdate',
@@ -562,4 +575,14 @@ export enum TrackEvent {
562
575
  * @internal
563
576
  */
564
577
  AudioTrackFeatureUpdate = 'audioTrackFeatureUpdate',
578
+
579
+ /**
580
+ * @beta
581
+ */
582
+ TranscriptionReceived = 'transcriptionReceived',
583
+
584
+ /**
585
+ * @experimental
586
+ */
587
+ TimeSyncUpdate = 'timeSyncUpdate',
565
588
  }
@@ -16,7 +16,7 @@ import type RemoteTrack from '../track/RemoteTrack';
16
16
  import type RemoteTrackPublication from '../track/RemoteTrackPublication';
17
17
  import { Track } from '../track/Track';
18
18
  import type { TrackPublication } from '../track/TrackPublication';
19
- import type { LoggerOptions } from '../types';
19
+ import type { LoggerOptions, TranscriptionSegment } from '../types';
20
20
 
21
21
  export enum ConnectionQuality {
22
22
  Excellent = 'excellent',
@@ -329,6 +329,10 @@ export type ParticipantEventCallbacks = {
329
329
  participantMetadataChanged: (prevMetadata: string | undefined, participant?: any) => void;
330
330
  participantNameChanged: (name: string) => void;
331
331
  dataReceived: (payload: Uint8Array, kind: DataPacket_Kind) => void;
332
+ transcriptionReceived: (
333
+ transcription: TranscriptionSegment[],
334
+ publication?: TrackPublication,
335
+ ) => void;
332
336
  isSpeakingChanged: (speaking: boolean) => void;
333
337
  connectionQualityChanged: (connectionQuality: ConnectionQuality) => void;
334
338
  trackStreamStateChanged: (
@@ -77,7 +77,20 @@ export default abstract class RemoteTrack<
77
77
  if (!this.monitorInterval) {
78
78
  this.monitorInterval = setInterval(() => this.monitorReceiver(), monitorFrequency);
79
79
  }
80
+ this.registerTimeSyncUpdate();
80
81
  }
81
82
 
82
83
  protected abstract monitorReceiver(): void;
84
+
85
+ registerTimeSyncUpdate() {
86
+ const loop = () => {
87
+ this.timeSyncHandle = requestAnimationFrame(() => loop());
88
+ const newTime = this.receiver?.getSynchronizationSources()[0]?.rtpTimestamp;
89
+ if (newTime && this.rtpTimestamp !== newTime) {
90
+ this.emit(TrackEvent.TimeSyncUpdate, newTime);
91
+ this.rtpTimestamp = newTime;
92
+ }
93
+ };
94
+ loop();
95
+ }
83
96
  }
@@ -53,6 +53,9 @@ export abstract class Track<
53
53
  */
54
54
  streamState: Track.StreamState = Track.StreamState.Active;
55
55
 
56
+ /** @internal */
57
+ rtpTimestamp: number | undefined;
58
+
56
59
  protected _mediaStreamTrack: MediaStreamTrack;
57
60
 
58
61
  protected _mediaStreamID: string;
@@ -63,6 +66,8 @@ export abstract class Track<
63
66
 
64
67
  private loggerContextCb: LoggerOptions['loggerContextCb'];
65
68
 
69
+ protected timeSyncHandle: number | undefined;
70
+
66
71
  protected _currentBitrate: number = 0;
67
72
 
68
73
  protected monitorInterval?: ReturnType<typeof setInterval>;
@@ -255,6 +260,9 @@ export abstract class Track<
255
260
  if (this.monitorInterval) {
256
261
  clearInterval(this.monitorInterval);
257
262
  }
263
+ if (this.timeSyncHandle) {
264
+ cancelAnimationFrame(this.timeSyncHandle);
265
+ }
258
266
  }
259
267
 
260
268
  /** @internal */
@@ -517,4 +525,5 @@ export type TrackEventCallbacks = {
517
525
  upstreamResumed: (track: any) => void;
518
526
  trackProcessorUpdate: (processor?: TrackProcessor<Track.Kind, any>) => void;
519
527
  audioTrackFeatureUpdate: (track: any, feature: AudioTrackFeature, enabled: boolean) => void;
528
+ timeSyncUpdate: (timestamp: number) => void;
520
529
  };
@@ -9,7 +9,7 @@ import { EventEmitter } from 'events';
9
9
  import type TypedEventEmitter from 'typed-emitter';
10
10
  import log, { LoggerNames, getLogger } from '../../logger';
11
11
  import { TrackEvent } from '../events';
12
- import type { LoggerOptions } from '../types';
12
+ import type { LoggerOptions, TranscriptionSegment } from '../types';
13
13
  import LocalAudioTrack from './LocalAudioTrack';
14
14
  import LocalVideoTrack from './LocalVideoTrack';
15
15
  import RemoteAudioTrack from './RemoteAudioTrack';
@@ -174,4 +174,6 @@ export type PublicationEventCallbacks = {
174
174
  prevStatus: TrackPublication.SubscriptionStatus,
175
175
  ) => void;
176
176
  subscriptionFailed: (error: SubscriptionError) => void;
177
+ transcriptionReceived: (transcription: TranscriptionSegment[]) => void;
178
+ timeSyncUpdate: (timestamp: number) => void;
177
179
  };
package/src/room/types.ts CHANGED
@@ -55,3 +55,12 @@ export type LoggerOptions = {
55
55
  loggerName?: string;
56
56
  loggerContextCb?: () => Record<string, unknown>;
57
57
  };
58
+
59
+ export interface TranscriptionSegment {
60
+ id: string;
61
+ text: string;
62
+ language: string;
63
+ startTime: number;
64
+ endTime: number;
65
+ final: boolean;
66
+ }
package/src/room/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ClientInfo, ClientInfo_SDK } from '@livekit/protocol';
1
+ import { ClientInfo, ClientInfo_SDK, Transcription as TranscriptionModel } from '@livekit/protocol';
2
2
  import { getBrowser } from '../utils/browserParser';
3
3
  import { protocolVersion, version } from '../version';
4
4
  import CriticalTimers from './timers';
@@ -6,7 +6,7 @@ import type LocalAudioTrack from './track/LocalAudioTrack';
6
6
  import type RemoteAudioTrack from './track/RemoteAudioTrack';
7
7
  import { VideoCodec, videoCodecs } from './track/options';
8
8
  import { getNewAudioContext } from './track/utils';
9
- import type { LiveKitReactNativeInfo } from './types';
9
+ import type { LiveKitReactNativeInfo, TranscriptionSegment } from './types';
10
10
 
11
11
  const separator = '|';
12
12
  export const ddExtensionURI =
@@ -527,3 +527,18 @@ export function toHttpUrl(url: string): string {
527
527
  }
528
528
  return url;
529
529
  }
530
+
531
+ export function extractTranscriptionSegments(
532
+ transcription: TranscriptionModel,
533
+ ): TranscriptionSegment[] {
534
+ return transcription.segments.map(({ id, text, language, startTime, endTime, final }) => {
535
+ return {
536
+ id,
537
+ text,
538
+ startTime: Number.parseInt(startTime.toString()),
539
+ endTime: Number.parseInt(endTime.toString()),
540
+ final,
541
+ language,
542
+ };
543
+ });
544
+ }