livekit-client 1.12.0 → 1.12.2

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