livekit-client 2.1.1 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
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
+ }