livekit-client 1.12.0 → 1.12.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 (166) hide show
  1. package/README.md +19 -1
  2. package/dist/livekit-client.e2ee.worker.js +1 -1
  3. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  4. package/dist/livekit-client.e2ee.worker.mjs +442 -334
  5. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  6. package/dist/livekit-client.esm.mjs +12303 -14499
  7. package/dist/livekit-client.esm.mjs.map +1 -1
  8. package/dist/livekit-client.umd.js +1 -1
  9. package/dist/livekit-client.umd.js.map +1 -1
  10. package/dist/src/api/SignalClient.d.ts +2 -2
  11. package/dist/src/api/SignalClient.d.ts.map +1 -1
  12. package/dist/src/connectionHelper/ConnectionCheck.d.ts +3 -2
  13. package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
  14. package/dist/src/connectionHelper/checks/Checker.d.ts +3 -2
  15. package/dist/src/connectionHelper/checks/Checker.d.ts.map +1 -1
  16. package/dist/src/connectionHelper/checks/webrtc.d.ts.map +1 -1
  17. package/dist/src/connectionHelper/checks/websocket.d.ts.map +1 -1
  18. package/dist/src/e2ee/E2eeManager.d.ts +4 -2
  19. package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
  20. package/dist/src/e2ee/KeyProvider.d.ts +4 -2
  21. package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
  22. package/dist/src/e2ee/constants.d.ts +1 -0
  23. package/dist/src/e2ee/constants.d.ts.map +1 -1
  24. package/dist/src/e2ee/types.d.ts +1 -0
  25. package/dist/src/e2ee/types.d.ts.map +1 -1
  26. package/dist/src/e2ee/worker/FrameCryptor.d.ts +4 -3
  27. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  28. package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts +21 -2
  29. package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
  30. package/dist/src/index.d.ts +1 -1
  31. package/dist/src/index.d.ts.map +1 -1
  32. package/dist/src/proto/livekit_models_pb.d.ts +1264 -0
  33. package/dist/src/proto/livekit_models_pb.d.ts.map +1 -0
  34. package/dist/src/proto/livekit_rtc_pb.d.ts +1373 -0
  35. package/dist/src/proto/livekit_rtc_pb.d.ts.map +1 -0
  36. package/dist/src/room/PCTransport.d.ts +2 -1
  37. package/dist/src/room/PCTransport.d.ts.map +1 -1
  38. package/dist/src/room/RTCEngine.d.ts +9 -5
  39. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  40. package/dist/src/room/RegionUrlProvider.d.ts +4 -1
  41. package/dist/src/room/RegionUrlProvider.d.ts.map +1 -1
  42. package/dist/src/room/Room.d.ts +15 -11
  43. package/dist/src/room/Room.d.ts.map +1 -1
  44. package/dist/src/room/participant/LocalParticipant.d.ts +2 -2
  45. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  46. package/dist/src/room/participant/Participant.d.ts +5 -3
  47. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  48. package/dist/src/room/participant/ParticipantTrackPermission.d.ts +1 -1
  49. package/dist/src/room/participant/ParticipantTrackPermission.d.ts.map +1 -1
  50. package/dist/src/room/participant/RemoteParticipant.d.ts +8 -7
  51. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  52. package/dist/src/room/timers.d.ts +5 -4
  53. package/dist/src/room/timers.d.ts.map +1 -1
  54. package/dist/src/room/track/LocalTrack.d.ts +3 -0
  55. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  56. package/dist/src/room/track/LocalTrackPublication.d.ts +1 -1
  57. package/dist/src/room/track/LocalTrackPublication.d.ts.map +1 -1
  58. package/dist/src/room/track/LocalVideoTrack.d.ts +2 -2
  59. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  60. package/dist/src/room/track/RemoteTrackPublication.d.ts +1 -1
  61. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  62. package/dist/src/room/track/Track.d.ts +6 -4
  63. package/dist/src/room/track/Track.d.ts.map +1 -1
  64. package/dist/src/room/track/TrackPublication.d.ts +7 -5
  65. package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
  66. package/dist/src/room/track/create.d.ts.map +1 -1
  67. package/dist/src/room/track/options.d.ts +7 -0
  68. package/dist/src/room/track/options.d.ts.map +1 -1
  69. package/dist/src/room/track/utils.d.ts +5 -1
  70. package/dist/src/room/track/utils.d.ts.map +1 -1
  71. package/dist/src/room/utils.d.ts +3 -1
  72. package/dist/src/room/utils.d.ts.map +1 -1
  73. package/dist/src/test/mocks.d.ts +4 -3
  74. package/dist/src/test/mocks.d.ts.map +1 -1
  75. package/dist/src/utils/browserParser.d.ts +2 -0
  76. package/dist/src/utils/browserParser.d.ts.map +1 -1
  77. package/dist/ts4.2/src/api/SignalClient.d.ts +2 -2
  78. package/dist/ts4.2/src/connectionHelper/ConnectionCheck.d.ts +3 -2
  79. package/dist/ts4.2/src/connectionHelper/checks/Checker.d.ts +3 -2
  80. package/dist/ts4.2/src/e2ee/E2eeManager.d.ts +4 -2
  81. package/dist/ts4.2/src/e2ee/KeyProvider.d.ts +4 -2
  82. package/dist/ts4.2/src/e2ee/constants.d.ts +1 -0
  83. package/dist/ts4.2/src/e2ee/types.d.ts +1 -0
  84. package/dist/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +4 -3
  85. package/dist/ts4.2/src/e2ee/worker/ParticipantKeyHandler.d.ts +21 -2
  86. package/dist/ts4.2/src/index.d.ts +1 -1
  87. package/dist/ts4.2/src/proto/livekit_models_pb.d.ts +1264 -0
  88. package/dist/ts4.2/src/proto/livekit_rtc_pb.d.ts +1373 -0
  89. package/dist/ts4.2/src/room/PCTransport.d.ts +2 -1
  90. package/dist/ts4.2/src/room/RTCEngine.d.ts +9 -5
  91. package/dist/ts4.2/src/room/RegionUrlProvider.d.ts +4 -1
  92. package/dist/ts4.2/src/room/Room.d.ts +15 -11
  93. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +2 -2
  94. package/dist/ts4.2/src/room/participant/Participant.d.ts +5 -3
  95. package/dist/ts4.2/src/room/participant/ParticipantTrackPermission.d.ts +1 -1
  96. package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +8 -7
  97. package/dist/ts4.2/src/room/timers.d.ts +5 -4
  98. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +3 -0
  99. package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +1 -1
  100. package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -2
  101. package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +1 -1
  102. package/dist/ts4.2/src/room/track/Track.d.ts +6 -4
  103. package/dist/ts4.2/src/room/track/TrackPublication.d.ts +7 -5
  104. package/dist/ts4.2/src/room/track/options.d.ts +7 -0
  105. package/dist/ts4.2/src/room/track/utils.d.ts +5 -1
  106. package/dist/ts4.2/src/room/utils.d.ts +3 -1
  107. package/dist/ts4.2/src/test/mocks.d.ts +4 -3
  108. package/dist/ts4.2/src/utils/browserParser.d.ts +2 -0
  109. package/package.json +10 -10
  110. package/src/api/SignalClient.ts +104 -101
  111. package/src/connectionHelper/ConnectionCheck.ts +3 -2
  112. package/src/connectionHelper/checks/Checker.ts +3 -3
  113. package/src/connectionHelper/checks/webrtc.ts +66 -2
  114. package/src/connectionHelper/checks/websocket.ts +4 -0
  115. package/src/e2ee/E2eeManager.ts +4 -3
  116. package/src/e2ee/KeyProvider.ts +3 -2
  117. package/src/e2ee/constants.ts +4 -0
  118. package/src/e2ee/types.ts +1 -0
  119. package/src/e2ee/worker/FrameCryptor.test.ts +1 -3
  120. package/src/e2ee/worker/FrameCryptor.ts +14 -16
  121. package/src/e2ee/worker/ParticipantKeyHandler.ts +48 -2
  122. package/src/e2ee/worker/e2ee.worker.ts +12 -6
  123. package/src/index.ts +1 -1
  124. package/src/proto/livekit_models_pb.ts +2096 -0
  125. package/src/proto/livekit_rtc_pb.ts +2332 -0
  126. package/src/room/PCTransport.ts +1 -1
  127. package/src/room/RTCEngine.ts +24 -18
  128. package/src/room/RegionUrlProvider.ts +11 -2
  129. package/src/room/Room.test.ts +1 -0
  130. package/src/room/Room.ts +175 -86
  131. package/src/room/participant/LocalParticipant.ts +43 -59
  132. package/src/room/participant/Participant.ts +6 -4
  133. package/src/room/participant/ParticipantTrackPermission.ts +3 -3
  134. package/src/room/participant/RemoteParticipant.ts +24 -21
  135. package/src/room/participant/publishUtils.test.ts +1 -0
  136. package/src/room/track/LocalTrack.ts +24 -9
  137. package/src/room/track/LocalTrackPublication.ts +1 -1
  138. package/src/room/track/LocalVideoTrack.test.ts +2 -1
  139. package/src/room/track/LocalVideoTrack.ts +22 -22
  140. package/src/room/track/RemoteTrackPublication.ts +12 -7
  141. package/src/room/track/RemoteVideoTrack.test.ts +5 -4
  142. package/src/room/track/Track.ts +9 -6
  143. package/src/room/track/TrackPublication.ts +7 -5
  144. package/src/room/track/create.ts +18 -17
  145. package/src/room/track/facingMode.test.ts +1 -0
  146. package/src/room/track/options.ts +6 -0
  147. package/src/room/track/utils.test.ts +1 -0
  148. package/src/room/track/utils.ts +44 -2
  149. package/src/room/utils.test.ts +16 -0
  150. package/src/room/utils.ts +20 -4
  151. package/src/test/mocks.ts +7 -5
  152. package/src/utils/AsyncQueue.test.ts +1 -0
  153. package/src/utils/browserParser.test.ts +33 -3
  154. package/src/utils/browserParser.ts +5 -0
  155. package/dist/src/proto/google/protobuf/timestamp.d.ts +0 -146
  156. package/dist/src/proto/google/protobuf/timestamp.d.ts.map +0 -1
  157. package/dist/src/proto/livekit_models.d.ts +0 -2399
  158. package/dist/src/proto/livekit_models.d.ts.map +0 -1
  159. package/dist/src/proto/livekit_rtc.d.ts +0 -14352
  160. package/dist/src/proto/livekit_rtc.d.ts.map +0 -1
  161. package/dist/ts4.2/src/proto/google/protobuf/timestamp.d.ts +0 -150
  162. package/dist/ts4.2/src/proto/livekit_models.d.ts +0 -2659
  163. package/dist/ts4.2/src/proto/livekit_rtc.d.ts +0 -15764
  164. package/src/proto/google/protobuf/timestamp.ts +0 -230
  165. package/src/proto/livekit_models.ts +0 -4006
  166. package/src/proto/livekit_rtc.ts +0 -4672
@@ -1,8 +1,9 @@
1
- import EventEmitter from 'eventemitter3';
1
+ import { EventEmitter } from 'events';
2
+ import type TypedEventEmitter from 'typed-emitter';
2
3
  import type { SignalClient } from '../../api/SignalClient';
3
4
  import log from '../../logger';
4
- import { TrackSource, TrackType } from '../../proto/livekit_models';
5
- import { StreamState as ProtoStreamState } from '../../proto/livekit_rtc';
5
+ import { TrackSource, TrackType } from '../../proto/livekit_models_pb';
6
+ import { StreamState as ProtoStreamState } from '../../proto/livekit_rtc_pb';
6
7
  import { TrackEvent } from '../events';
7
8
  import { isFireFox, isSafari, isWeb } from '../utils';
8
9
 
@@ -12,7 +13,7 @@ const BACKGROUND_REACTION_DELAY = 5000;
12
13
  // Safari tracks which audio elements have been "blessed" by the user.
13
14
  const recycledElements: Array<HTMLAudioElement> = [];
14
15
 
15
- export abstract class Track extends EventEmitter<TrackEventCallbacks> {
16
+ export abstract class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEventCallbacks>) {
16
17
  kind: Track.Kind;
17
18
 
18
19
  attachedElements: HTMLMediaElement[] = [];
@@ -51,6 +52,7 @@ export abstract class Track extends EventEmitter<TrackEventCallbacks> {
51
52
 
52
53
  protected constructor(mediaTrack: MediaStreamTrack, kind: Track.Kind) {
53
54
  super();
55
+ this.setMaxListeners(100);
54
56
  this.kind = kind;
55
57
  this._mediaStreamTrack = mediaTrack;
56
58
  this._mediaStreamID = mediaTrack.id;
@@ -368,7 +370,8 @@ export namespace Track {
368
370
  case Kind.Video:
369
371
  return TrackType.VIDEO;
370
372
  default:
371
- return TrackType.UNRECOGNIZED;
373
+ // FIXME this was UNRECOGNIZED before
374
+ return TrackType.DATA;
372
375
  }
373
376
  }
374
377
 
@@ -396,7 +399,7 @@ export namespace Track {
396
399
  case Source.ScreenShareAudio:
397
400
  return TrackSource.SCREEN_SHARE_AUDIO;
398
401
  default:
399
- return TrackSource.UNRECOGNIZED;
402
+ return TrackSource.UNKNOWN;
400
403
  }
401
404
  }
402
405
 
@@ -1,8 +1,9 @@
1
- import EventEmitter from 'eventemitter3';
1
+ import { EventEmitter } from 'events';
2
+ import type TypedEventEmitter from 'typed-emitter';
2
3
  import log from '../../logger';
3
- import { Encryption_Type } from '../../proto/livekit_models';
4
- import type { SubscriptionError, TrackInfo } from '../../proto/livekit_models';
5
- import type { UpdateSubscription, UpdateTrackSettings } from '../../proto/livekit_rtc';
4
+ import { Encryption_Type } from '../../proto/livekit_models_pb';
5
+ import type { SubscriptionError, TrackInfo } from '../../proto/livekit_models_pb';
6
+ import type { UpdateSubscription, UpdateTrackSettings } from '../../proto/livekit_rtc_pb';
6
7
  import { TrackEvent } from '../events';
7
8
  import LocalAudioTrack from './LocalAudioTrack';
8
9
  import LocalVideoTrack from './LocalVideoTrack';
@@ -11,7 +12,7 @@ import type RemoteTrack from './RemoteTrack';
11
12
  import RemoteVideoTrack from './RemoteVideoTrack';
12
13
  import { Track } from './Track';
13
14
 
14
- export class TrackPublication extends EventEmitter<PublicationEventCallbacks> {
15
+ export class TrackPublication extends (EventEmitter as new () => TypedEventEmitter<PublicationEventCallbacks>) {
15
16
  kind: Track.Kind;
16
17
 
17
18
  trackName: string;
@@ -40,6 +41,7 @@ export class TrackPublication extends EventEmitter<PublicationEventCallbacks> {
40
41
 
41
42
  constructor(kind: Track.Kind, id: string, name: string) {
42
43
  super();
44
+ this.setMaxListeners(100);
43
45
  this.kind = kind;
44
46
  this.trackSid = id;
45
47
  this.trackName = name;
@@ -6,14 +6,18 @@ import LocalAudioTrack from './LocalAudioTrack';
6
6
  import type LocalTrack from './LocalTrack';
7
7
  import LocalVideoTrack from './LocalVideoTrack';
8
8
  import { Track } from './Track';
9
- import { VideoPresets } from './options';
9
+ import { ScreenSharePresets } from './options';
10
10
  import type {
11
11
  AudioCaptureOptions,
12
12
  CreateLocalTracksOptions,
13
13
  ScreenShareCaptureOptions,
14
14
  VideoCaptureOptions,
15
15
  } from './options';
16
- import { constraintsForOptions, mergeDefaultOptions } from './utils';
16
+ import {
17
+ constraintsForOptions,
18
+ mergeDefaultOptions,
19
+ screenCaptureToDisplayMediaStreamOptions,
20
+ } from './utils';
17
21
 
18
22
  /**
19
23
  * Creates a local video and audio track at the same time. When acquiring both
@@ -57,6 +61,15 @@ export async function createLocalTracks(
57
61
  if (typeof conOrBool !== 'boolean') {
58
62
  trackConstraints = conOrBool;
59
63
  }
64
+
65
+ // update the constraints with the device id the user gave permissions to in the permission prompt
66
+ // otherwise each track restart (e.g. mute - unmute) will try to initialize the device again -> causing additional permission prompts
67
+ if (trackConstraints) {
68
+ trackConstraints.deviceId = mediaStreamTrack.getSettings().deviceId;
69
+ } else {
70
+ trackConstraints = { deviceId: mediaStreamTrack.getSettings().deviceId };
71
+ }
72
+
60
73
  const track = mediaTrackToLocalTrack(mediaStreamTrack, trackConstraints);
61
74
  if (track.kind === Track.Kind.Video) {
62
75
  track.source = Track.Source.Camera;
@@ -104,27 +117,15 @@ export async function createLocalScreenTracks(
104
117
  options = {};
105
118
  }
106
119
  if (options.resolution === undefined) {
107
- options.resolution = VideoPresets.h1080.resolution;
108
- }
109
-
110
- let videoConstraints: MediaTrackConstraints | boolean = true;
111
- if (options.resolution) {
112
- videoConstraints = {
113
- width: options.resolution.width,
114
- height: options.resolution.height,
115
- };
120
+ options.resolution = ScreenSharePresets.h1080fps15.resolution;
116
121
  }
117
122
 
118
123
  if (navigator.mediaDevices.getDisplayMedia === undefined) {
119
124
  throw new DeviceUnsupportedError('getDisplayMedia not supported');
120
125
  }
121
126
 
122
- // typescript definition is missing getDisplayMedia: https://github.com/microsoft/TypeScript/issues/33232
123
- // @ts-ignore
124
- const stream: MediaStream = await navigator.mediaDevices.getDisplayMedia({
125
- audio: options.audio ?? false,
126
- video: videoConstraints,
127
- });
127
+ const constraints = screenCaptureToDisplayMediaStreamOptions(options);
128
+ const stream: MediaStream = await navigator.mediaDevices.getDisplayMedia(constraints);
128
129
 
129
130
  const tracks = stream.getVideoTracks();
130
131
  if (tracks.length === 0) {
@@ -1,3 +1,4 @@
1
+ import { describe, expect, test } from 'vitest';
1
2
  import { facingModeFromDeviceLabel } from './facingMode';
2
3
 
3
4
  describe('Test facingMode detection', () => {
@@ -147,6 +147,12 @@ export interface ScreenShareCaptureOptions {
147
147
  */
148
148
  audio?: boolean | AudioCaptureOptions;
149
149
 
150
+ /**
151
+ * only allows for 'true' and chrome allows for additional options to be passed in
152
+ * https://developer.chrome.com/docs/web-platform/screen-sharing-controls/#displaySurface
153
+ */
154
+ video?: true | { displaySurface?: 'window' | 'browser' | 'monitor' };
155
+
150
156
  /** capture resolution, defaults to full HD */
151
157
  resolution?: VideoResolution;
152
158
 
@@ -1,3 +1,4 @@
1
+ import { describe, expect, it } from 'vitest';
1
2
  import { AudioCaptureOptions, VideoCaptureOptions, VideoPresets } from './options';
2
3
  import { constraintsForOptions, mergeDefaultOptions } from './utils';
3
4
 
@@ -1,6 +1,11 @@
1
- import { sleep } from '../utils';
1
+ import { isSafari, sleep } from '../utils';
2
2
  import { Track } from './Track';
3
- import type { AudioCaptureOptions, CreateLocalTracksOptions, VideoCaptureOptions } from './options';
3
+ import type {
4
+ AudioCaptureOptions,
5
+ CreateLocalTracksOptions,
6
+ ScreenShareCaptureOptions,
7
+ VideoCaptureOptions,
8
+ } from './options';
4
9
  import type { AudioTrack } from './types';
5
10
 
6
11
  export function mergeDefaultOptions(
@@ -139,3 +144,40 @@ export function sourceToKind(source: Track.Source): MediaDeviceKind | undefined
139
144
  return undefined;
140
145
  }
141
146
  }
147
+
148
+ /**
149
+ * @internal
150
+ */
151
+ export function screenCaptureToDisplayMediaStreamOptions(
152
+ options: ScreenShareCaptureOptions,
153
+ ): DisplayMediaStreamOptions {
154
+ let videoConstraints: MediaTrackConstraints | boolean = options.video ?? true;
155
+ if (options.resolution) {
156
+ videoConstraints = typeof videoConstraints === 'boolean' ? {} : videoConstraints;
157
+ if (isSafari()) {
158
+ videoConstraints = {
159
+ ...videoConstraints,
160
+ width: { max: options.resolution.width },
161
+ height: { max: options.resolution.height },
162
+ frameRate: options.resolution.frameRate,
163
+ };
164
+ } else {
165
+ videoConstraints = {
166
+ ...videoConstraints,
167
+ width: { ideal: options.resolution.width },
168
+ height: { ideal: options.resolution.height },
169
+ frameRate: options.resolution.frameRate,
170
+ };
171
+ }
172
+ }
173
+
174
+ return {
175
+ audio: options.audio ?? false,
176
+ video: videoConstraints,
177
+ // @ts-expect-error support for experimental display media features
178
+ controller: options.controller,
179
+ selfBrowserSurface: options.selfBrowserSurface,
180
+ surfaceSwitching: options.surfaceSwitching,
181
+ systemAudio: options.systemAudio,
182
+ };
183
+ }
@@ -0,0 +1,16 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { toWebsocketUrl } from './utils';
3
+
4
+ describe('toWebsocketUrl', () => {
5
+ it('leaves wss urls alone', () => {
6
+ expect(toWebsocketUrl('ws://mywebsite.com')).toEqual('ws://mywebsite.com');
7
+ });
8
+
9
+ it('converts https to wss', () => {
10
+ expect(toWebsocketUrl('https://mywebsite.com')).toEqual('wss://mywebsite.com');
11
+ });
12
+
13
+ it('does not convert other parts of URL', () => {
14
+ expect(toWebsocketUrl('https://httpsmywebsite.com')).toEqual('wss://httpsmywebsite.com');
15
+ });
16
+ });
package/src/room/utils.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { ClientInfo, ClientInfo_SDK } from '../proto/livekit_models';
2
- import { getBrowser } from '../utils/browserParser';
1
+ import { ClientInfo, ClientInfo_SDK } from '../proto/livekit_models_pb';
3
2
  import type { DetectableBrowser } from '../utils/browserParser';
3
+ import { getBrowser } from '../utils/browserParser';
4
4
  import { protocolVersion, version } from '../version';
5
5
  import type LocalAudioTrack from './track/LocalAudioTrack';
6
6
  import type RemoteAudioTrack from './track/RemoteAudioTrack';
@@ -148,7 +148,9 @@ export function isReactNative(): boolean {
148
148
  }
149
149
 
150
150
  export function isCloud(serverUrl: URL) {
151
- return serverUrl.hostname.endsWith('.livekit.cloud');
151
+ return (
152
+ serverUrl.hostname.endsWith('.livekit.cloud') || serverUrl.hostname.endsWith('.livekit.run')
153
+ );
152
154
  }
153
155
 
154
156
  function getLKReactNativeInfo(): LiveKitReactNativeInfo | undefined {
@@ -244,7 +246,7 @@ export interface ObservableMediaElement extends HTMLMediaElement {
244
246
  }
245
247
 
246
248
  export function getClientInfo(): ClientInfo {
247
- const info = ClientInfo.fromPartial({
249
+ const info = new ClientInfo({
248
250
  sdk: ClientInfo_SDK.JS,
249
251
  protocol: protocolVersion,
250
252
  version,
@@ -483,3 +485,17 @@ export function unwrapConstraint(constraint: ConstrainDOMString): string {
483
485
  }
484
486
  throw Error('could not unwrap constraint');
485
487
  }
488
+
489
+ export function toWebsocketUrl(url: string): string {
490
+ if (url.startsWith('http')) {
491
+ return url.replace(/^(http)/, 'ws');
492
+ }
493
+ return url;
494
+ }
495
+
496
+ export function toHttpUrl(url: string): string {
497
+ if (url.startsWith('ws')) {
498
+ return url.replace(/^(ws)/, 'http');
499
+ }
500
+ return url;
501
+ }
package/src/test/mocks.ts CHANGED
@@ -1,16 +1,18 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+ import { MockedClass, vi } from 'vitest';
1
3
  import { SignalClient } from '../api/SignalClient';
2
4
  import RTCEngine from '../room/RTCEngine';
3
5
 
4
- jest.mock('../api/SignalClient');
5
- jest.mock('../room/RTCEngine');
6
+ vi.mock('../api/SignalClient');
7
+ vi.mock('../room/RTCEngine');
6
8
 
7
9
  // mock helpers for testing
8
10
 
9
11
  const mocks = {
10
- SignalClient: SignalClient as jest.MockedClass<typeof SignalClient>,
11
- RTCEngine: RTCEngine as jest.MockedClass<typeof RTCEngine>,
12
+ SignalClient: SignalClient as MockedClass<typeof SignalClient>,
13
+ RTCEngine: RTCEngine as MockedClass<typeof RTCEngine>,
12
14
  MockLocalVideoTrack: {
13
- stop: jest.fn(),
15
+ stop: vi.fn(),
14
16
  },
15
17
  };
16
18
 
@@ -1,3 +1,4 @@
1
+ import { describe, expect, it } from 'vitest';
1
2
  import { sleep } from '../room/utils';
2
3
  import { AsyncQueue } from './AsyncQueue';
3
4
 
@@ -1,33 +1,63 @@
1
+ import { describe, expect, it } from 'vitest';
1
2
  import { compareVersions } from '../room/utils';
2
3
  import { getBrowser } from './browserParser';
3
4
 
4
5
  describe('browser parser', () => {
5
- const safariUA =
6
+ const macOSSafariUA =
6
7
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15';
8
+
9
+ const iOSSafariUA =
10
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1';
11
+
7
12
  const firefoxUA =
8
13
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/112.0';
9
14
 
15
+ const iOSFirefoxUA =
16
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/115.0 Mobile/15E148 Safari/605.1.15';
17
+
10
18
  const chromeUA =
11
19
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36';
12
20
 
21
+ const iOSChromeUA =
22
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/115.0.5790.130 Mobile/15E148 Safari/604.11';
23
+
13
24
  const braveUA =
14
25
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36';
15
26
 
16
- it('parses Safari correctly', () => {
17
- const details = getBrowser(safariUA, true);
27
+ it('parses Safari macOS correctly', () => {
28
+ const details = getBrowser(macOSSafariUA, true);
18
29
  expect(details?.name).toBe('Safari');
19
30
  expect(details?.version).toBe('16.3');
31
+ expect(details?.os).toBe('macOS');
32
+ });
33
+ it('parses Safari iOS correctly', () => {
34
+ const details = getBrowser(iOSSafariUA, true);
35
+ expect(details?.name).toBe('Safari');
36
+ expect(details?.version).toBe('16.5');
37
+ expect(details?.os).toBe('iOS');
20
38
  });
21
39
  it('parses Firefox correctly', () => {
22
40
  const details = getBrowser(firefoxUA, true);
23
41
  expect(details?.name).toBe('Firefox');
24
42
  expect(details?.version).toBe('112.0');
25
43
  });
44
+ it('parses iOS Firefox correctly', () => {
45
+ const details = getBrowser(iOSFirefoxUA, true);
46
+ expect(details?.name).toBe('Firefox');
47
+ expect(details?.version).toBe('115.0');
48
+ expect(details?.os).toBe('iOS');
49
+ });
26
50
  it('parses Chrome correctly', () => {
27
51
  const details = getBrowser(chromeUA, true);
28
52
  expect(details?.name).toBe('Chrome');
29
53
  expect(details?.version).toBe('112.0.0.0');
30
54
  });
55
+ it('parses iOS Chrome correctly', () => {
56
+ const details = getBrowser(iOSChromeUA, true);
57
+ expect(details?.name).toBe('Chrome');
58
+ expect(details?.version).toBe('115.0.5790.130');
59
+ expect(details?.os).toBe('iOS');
60
+ });
31
61
  it('detects brave as chromium based', () => {
32
62
  const details = getBrowser(braveUA, true);
33
63
  expect(details?.name).toBe('Chrome');
@@ -4,10 +4,12 @@
4
4
  const commonVersionIdentifier = /version\/(\d+(\.?_?\d+)+)/i;
5
5
 
6
6
  export type DetectableBrowser = 'Chrome' | 'Firefox' | 'Safari';
7
+ export type DetectableOS = 'iOS' | 'macOS';
7
8
 
8
9
  export type BrowserDetails = {
9
10
  name: DetectableBrowser;
10
11
  version: string;
12
+ os?: DetectableOS;
11
13
  };
12
14
 
13
15
  let browserDetails: BrowserDetails | undefined;
@@ -34,6 +36,7 @@ const browsersList = [
34
36
  const browser: BrowserDetails = {
35
37
  name: 'Firefox',
36
38
  version: getMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i, ua),
39
+ os: ua.toLowerCase().includes('fxios') ? 'iOS' : undefined,
37
40
  };
38
41
  return browser;
39
42
  },
@@ -44,6 +47,7 @@ const browsersList = [
44
47
  const browser: BrowserDetails = {
45
48
  name: 'Chrome',
46
49
  version: getMatch(/(?:chrome|chromium|crios|crmo)\/(\d+(\.?_?\d+)+)/i, ua),
50
+ os: ua.toLowerCase().includes('crios') ? 'iOS' : undefined,
47
51
  };
48
52
 
49
53
  return browser;
@@ -56,6 +60,7 @@ const browsersList = [
56
60
  const browser: BrowserDetails = {
57
61
  name: 'Safari',
58
62
  version: getMatch(commonVersionIdentifier, ua),
63
+ os: ua.includes('mobile/') ? 'iOS' : 'macOS',
59
64
  };
60
65
 
61
66
  return browser;
@@ -1,146 +0,0 @@
1
- import _m0 from "protobufjs/minimal";
2
- export declare const protobufPackage = "google.protobuf";
3
- /**
4
- * A Timestamp represents a point in time independent of any time zone or local
5
- * calendar, encoded as a count of seconds and fractions of seconds at
6
- * nanosecond resolution. The count is relative to an epoch at UTC midnight on
7
- * January 1, 1970, in the proleptic Gregorian calendar which extends the
8
- * Gregorian calendar backwards to year one.
9
- *
10
- * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
11
- * second table is needed for interpretation, using a [24-hour linear
12
- * smear](https://developers.google.com/time/smear).
13
- *
14
- * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
15
- * restricting to that range, we ensure that we can convert to and from [RFC
16
- * 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
17
- *
18
- * # Examples
19
- *
20
- * Example 1: Compute Timestamp from POSIX `time()`.
21
- *
22
- * Timestamp timestamp;
23
- * timestamp.set_seconds(time(NULL));
24
- * timestamp.set_nanos(0);
25
- *
26
- * Example 2: Compute Timestamp from POSIX `gettimeofday()`.
27
- *
28
- * struct timeval tv;
29
- * gettimeofday(&tv, NULL);
30
- *
31
- * Timestamp timestamp;
32
- * timestamp.set_seconds(tv.tv_sec);
33
- * timestamp.set_nanos(tv.tv_usec * 1000);
34
- *
35
- * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
36
- *
37
- * FILETIME ft;
38
- * GetSystemTimeAsFileTime(&ft);
39
- * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
40
- *
41
- * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
42
- * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
43
- * Timestamp timestamp;
44
- * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
45
- * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
46
- *
47
- * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
48
- *
49
- * long millis = System.currentTimeMillis();
50
- *
51
- * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
52
- * .setNanos((int) ((millis % 1000) * 1000000)).build();
53
- *
54
- * Example 5: Compute Timestamp from Java `Instant.now()`.
55
- *
56
- * Instant now = Instant.now();
57
- *
58
- * Timestamp timestamp =
59
- * Timestamp.newBuilder().setSeconds(now.getEpochSecond())
60
- * .setNanos(now.getNano()).build();
61
- *
62
- * Example 6: Compute Timestamp from current time in Python.
63
- *
64
- * timestamp = Timestamp()
65
- * timestamp.GetCurrentTime()
66
- *
67
- * # JSON Mapping
68
- *
69
- * In JSON format, the Timestamp type is encoded as a string in the
70
- * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
71
- * format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
72
- * where {year} is always expressed using four digits while {month}, {day},
73
- * {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
74
- * seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
75
- * are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
76
- * is required. A proto3 JSON serializer should always use UTC (as indicated by
77
- * "Z") when printing the Timestamp type and a proto3 JSON parser should be
78
- * able to accept both UTC and other timezones (as indicated by an offset).
79
- *
80
- * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
81
- * 01:30 UTC on January 15, 2017.
82
- *
83
- * In JavaScript, one can convert a Date object to this format using the
84
- * standard
85
- * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
86
- * method. In Python, a standard `datetime.datetime` object can be converted
87
- * to this format using
88
- * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
89
- * the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
90
- * the Joda Time's [`ISODateTimeFormat.dateTime()`](
91
- * http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
92
- * ) to obtain a formatter capable of generating timestamps in this format.
93
- */
94
- export interface Timestamp {
95
- /**
96
- * Represents seconds of UTC time since Unix epoch
97
- * 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
98
- * 9999-12-31T23:59:59Z inclusive.
99
- */
100
- seconds: number;
101
- /**
102
- * Non-negative fractions of a second at nanosecond resolution. Negative
103
- * second values with fractions must still have non-negative nanos values
104
- * that count forward in time. Must be from 0 to 999,999,999
105
- * inclusive.
106
- */
107
- nanos: number;
108
- }
109
- export declare const Timestamp: {
110
- encode(message: Timestamp, writer?: _m0.Writer): _m0.Writer;
111
- decode(input: _m0.Reader | Uint8Array, length?: number): Timestamp;
112
- fromJSON(object: any): Timestamp;
113
- toJSON(message: Timestamp): unknown;
114
- create<I extends {
115
- seconds?: number | undefined;
116
- nanos?: number | undefined;
117
- } & {
118
- seconds?: number | undefined;
119
- nanos?: number | undefined;
120
- } & { [K in Exclude<keyof I, keyof Timestamp>]: never; }>(base?: I | undefined): Timestamp;
121
- fromPartial<I_1 extends {
122
- seconds?: number | undefined;
123
- nanos?: number | undefined;
124
- } & {
125
- seconds?: number | undefined;
126
- nanos?: number | undefined;
127
- } & { [K_1 in Exclude<keyof I_1, keyof Timestamp>]: never; }>(object: I_1): Timestamp;
128
- };
129
- type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
130
- export type DeepPartial<T> = T extends Builtin ? T : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {
131
- $case: string;
132
- } ? {
133
- [K in keyof Omit<T, "$case">]?: DeepPartial<T[K]>;
134
- } & {
135
- $case: T["$case"];
136
- } : T extends {} ? {
137
- [K in keyof T]?: DeepPartial<T[K]>;
138
- } : Partial<T>;
139
- type KeysOfUnion<T> = T extends T ? keyof T : never;
140
- export type Exact<P, I extends P> = P extends Builtin ? P : P & {
141
- [K in keyof P]: Exact<P[K], I[K]>;
142
- } & {
143
- [K in Exclude<keyof I, KeysOfUnion<P>>]: never;
144
- };
145
- export {};
146
- //# sourceMappingURL=timestamp.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"timestamp.d.ts","sourceRoot":"","sources":["../../../../../src/proto/google/protobuf/timestamp.ts"],"names":[],"mappings":"AAEA,OAAO,GAAG,MAAM,oBAAoB,CAAC;AAErC,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0FG;AACH,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;CACf;AAMD,eAAO,MAAM,SAAS;oBACJ,SAAS,WAAU,IAAI,MAAM,GAAyB,IAAI,MAAM;kBAUlE,IAAI,MAAM,GAAG,UAAU,WAAW,MAAM,GAAG,SAAS;qBA8BjD,GAAG,GAAG,SAAS;oBAOhB,SAAS,GAAG,OAAO;;;;;;;qFAO2B,SAAS;;;;;;;gFAIH,SAAS;CAM9E,CAAC;AAqBF,KAAK,OAAO,GAAG,IAAI,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAEpF,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,OAAO,GAAG,CAAC,GAC9C,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GACnH,CAAC,SAAS;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;KAAG,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG;IAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,CAAA;CAAE,GAC3G,CAAC,SAAS,EAAE,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GACrD,OAAO,CAAC,CAAC,CAAC,CAAC;AAEf,KAAK,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,GAAG,KAAK,CAAC;AACpD,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,OAAO,GAAG,CAAC,GACrD,CAAC,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG;KAAG,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK;CAAE,CAAC"}