livekit-client 0.17.4 → 0.17.6-rc2

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 (155) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +26 -20
  3. package/dist/api/SignalClient.d.ts +1 -0
  4. package/dist/connect.d.ts +2 -0
  5. package/dist/index.d.ts +2 -2
  6. package/dist/livekit-client.esm.js +17344 -0
  7. package/dist/livekit-client.esm.js.map +1 -0
  8. package/dist/livekit-client.umd.js +2 -0
  9. package/dist/livekit-client.umd.js.map +1 -0
  10. package/dist/logger.d.ts +22 -11
  11. package/dist/options.d.ts +4 -2
  12. package/dist/proto/google/protobuf/timestamp.d.ts +12 -2
  13. package/dist/proto/livekit_models.d.ts +524 -17
  14. package/dist/proto/livekit_rtc.d.ts +3449 -31
  15. package/dist/room/DeviceManager.d.ts +1 -1
  16. package/dist/room/RTCEngine.d.ts +1 -1
  17. package/dist/room/Room.d.ts +2 -2
  18. package/dist/room/events.d.ts +1 -1
  19. package/dist/room/participant/LocalParticipant.d.ts +9 -5
  20. package/dist/room/participant/RemoteParticipant.d.ts +9 -0
  21. package/dist/room/track/RemoteAudioTrack.d.ts +11 -0
  22. package/dist/room/track/options.d.ts +1 -1
  23. package/dist/test/mocks.d.ts +11 -0
  24. package/dist/version.d.ts +1 -1
  25. package/package.json +41 -16
  26. package/.eslintrc.js +0 -17
  27. package/.gitmodules +0 -3
  28. package/dist/api/RequestQueue.js +0 -61
  29. package/dist/api/RequestQueue.js.map +0 -1
  30. package/dist/api/SignalClient.js +0 -428
  31. package/dist/api/SignalClient.js.map +0 -1
  32. package/dist/connect.js +0 -130
  33. package/dist/connect.js.map +0 -1
  34. package/dist/index.js +0 -71
  35. package/dist/index.js.map +0 -1
  36. package/dist/logger.js +0 -24
  37. package/dist/logger.js.map +0 -1
  38. package/dist/options.js +0 -3
  39. package/dist/options.js.map +0 -1
  40. package/dist/proto/google/protobuf/timestamp.js +0 -93
  41. package/dist/proto/google/protobuf/timestamp.js.map +0 -1
  42. package/dist/proto/livekit_models.js +0 -2688
  43. package/dist/proto/livekit_models.js.map +0 -1
  44. package/dist/proto/livekit_rtc.js +0 -2995
  45. package/dist/proto/livekit_rtc.js.map +0 -1
  46. package/dist/room/DeviceManager.js +0 -62
  47. package/dist/room/DeviceManager.js.map +0 -1
  48. package/dist/room/PCTransport.js +0 -91
  49. package/dist/room/PCTransport.js.map +0 -1
  50. package/dist/room/RTCEngine.js +0 -562
  51. package/dist/room/RTCEngine.js.map +0 -1
  52. package/dist/room/Room.js +0 -759
  53. package/dist/room/Room.js.map +0 -1
  54. package/dist/room/errors.js +0 -68
  55. package/dist/room/errors.js.map +0 -1
  56. package/dist/room/events.js +0 -385
  57. package/dist/room/events.js.map +0 -1
  58. package/dist/room/participant/LocalParticipant.js +0 -647
  59. package/dist/room/participant/LocalParticipant.js.map +0 -1
  60. package/dist/room/participant/Participant.js +0 -189
  61. package/dist/room/participant/Participant.js.map +0 -1
  62. package/dist/room/participant/ParticipantTrackPermission.js +0 -16
  63. package/dist/room/participant/ParticipantTrackPermission.js.map +0 -1
  64. package/dist/room/participant/RemoteParticipant.js +0 -194
  65. package/dist/room/participant/RemoteParticipant.js.map +0 -1
  66. package/dist/room/participant/publishUtils.js +0 -189
  67. package/dist/room/participant/publishUtils.js.map +0 -1
  68. package/dist/room/participant/publishUtils.test.d.ts +0 -1
  69. package/dist/room/participant/publishUtils.test.js +0 -118
  70. package/dist/room/participant/publishUtils.test.js.map +0 -1
  71. package/dist/room/stats.js +0 -26
  72. package/dist/room/stats.js.map +0 -1
  73. package/dist/room/track/LocalAudioTrack.js +0 -153
  74. package/dist/room/track/LocalAudioTrack.js.map +0 -1
  75. package/dist/room/track/LocalTrack.js +0 -158
  76. package/dist/room/track/LocalTrack.js.map +0 -1
  77. package/dist/room/track/LocalTrackPublication.js +0 -64
  78. package/dist/room/track/LocalTrackPublication.js.map +0 -1
  79. package/dist/room/track/LocalVideoTrack.js +0 -297
  80. package/dist/room/track/LocalVideoTrack.js.map +0 -1
  81. package/dist/room/track/LocalVideoTrack.test.d.ts +0 -1
  82. package/dist/room/track/LocalVideoTrack.test.js +0 -68
  83. package/dist/room/track/LocalVideoTrack.test.js.map +0 -1
  84. package/dist/room/track/RemoteAudioTrack.js +0 -64
  85. package/dist/room/track/RemoteAudioTrack.js.map +0 -1
  86. package/dist/room/track/RemoteTrack.js +0 -49
  87. package/dist/room/track/RemoteTrack.js.map +0 -1
  88. package/dist/room/track/RemoteTrackPublication.js +0 -178
  89. package/dist/room/track/RemoteTrackPublication.js.map +0 -1
  90. package/dist/room/track/RemoteVideoTrack.js +0 -201
  91. package/dist/room/track/RemoteVideoTrack.js.map +0 -1
  92. package/dist/room/track/Track.js +0 -283
  93. package/dist/room/track/Track.js.map +0 -1
  94. package/dist/room/track/TrackPublication.js +0 -92
  95. package/dist/room/track/TrackPublication.js.map +0 -1
  96. package/dist/room/track/create.js +0 -131
  97. package/dist/room/track/create.js.map +0 -1
  98. package/dist/room/track/defaults.js +0 -21
  99. package/dist/room/track/defaults.js.map +0 -1
  100. package/dist/room/track/options.js +0 -100
  101. package/dist/room/track/options.js.map +0 -1
  102. package/dist/room/track/types.js +0 -3
  103. package/dist/room/track/types.js.map +0 -1
  104. package/dist/room/track/utils.js +0 -113
  105. package/dist/room/track/utils.js.map +0 -1
  106. package/dist/room/track/utils.test.d.ts +0 -1
  107. package/dist/room/track/utils.test.js +0 -85
  108. package/dist/room/track/utils.test.js.map +0 -1
  109. package/dist/room/utils.js +0 -79
  110. package/dist/room/utils.js.map +0 -1
  111. package/dist/version.js +0 -6
  112. package/dist/version.js.map +0 -1
  113. package/jest.config.js +0 -6
  114. package/src/api/RequestQueue.ts +0 -53
  115. package/src/api/SignalClient.ts +0 -499
  116. package/src/connect.ts +0 -100
  117. package/src/index.ts +0 -47
  118. package/src/logger.ts +0 -22
  119. package/src/options.ts +0 -149
  120. package/src/proto/google/protobuf/timestamp.ts +0 -222
  121. package/src/proto/livekit_models.ts +0 -3019
  122. package/src/proto/livekit_rtc.ts +0 -3677
  123. package/src/room/DeviceManager.ts +0 -57
  124. package/src/room/PCTransport.ts +0 -86
  125. package/src/room/RTCEngine.ts +0 -652
  126. package/src/room/Room.ts +0 -943
  127. package/src/room/errors.ts +0 -65
  128. package/src/room/events.ts +0 -424
  129. package/src/room/participant/LocalParticipant.ts +0 -734
  130. package/src/room/participant/Participant.ts +0 -269
  131. package/src/room/participant/ParticipantTrackPermission.ts +0 -32
  132. package/src/room/participant/RemoteParticipant.ts +0 -243
  133. package/src/room/participant/publishUtils.test.ts +0 -145
  134. package/src/room/participant/publishUtils.ts +0 -225
  135. package/src/room/stats.ts +0 -130
  136. package/src/room/track/LocalAudioTrack.ts +0 -137
  137. package/src/room/track/LocalTrack.ts +0 -161
  138. package/src/room/track/LocalTrackPublication.ts +0 -66
  139. package/src/room/track/LocalVideoTrack.test.ts +0 -70
  140. package/src/room/track/LocalVideoTrack.ts +0 -293
  141. package/src/room/track/RemoteAudioTrack.ts +0 -58
  142. package/src/room/track/RemoteTrack.ts +0 -62
  143. package/src/room/track/RemoteTrackPublication.ts +0 -198
  144. package/src/room/track/RemoteVideoTrack.ts +0 -235
  145. package/src/room/track/Track.ts +0 -343
  146. package/src/room/track/TrackPublication.ts +0 -120
  147. package/src/room/track/create.ts +0 -121
  148. package/src/room/track/defaults.ts +0 -23
  149. package/src/room/track/options.ts +0 -281
  150. package/src/room/track/types.ts +0 -20
  151. package/src/room/track/utils.test.ts +0 -93
  152. package/src/room/track/utils.ts +0 -115
  153. package/src/room/utils.ts +0 -70
  154. package/src/version.ts +0 -2
  155. package/tsconfig.eslint.json +0 -11
@@ -1,79 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.getClientInfo = exports.getIntersectionObserver = exports.getResizeObserver = exports.isWeb = exports.isMobile = exports.isSafari = exports.isFireFox = exports.sleep = exports.unpackStreamId = void 0;
13
- const livekit_models_1 = require("../proto/livekit_models");
14
- const version_1 = require("../version");
15
- const separator = '|';
16
- function unpackStreamId(packed) {
17
- const parts = packed.split(separator);
18
- if (parts.length > 1) {
19
- return [parts[0], packed.substr(parts[0].length + 1)];
20
- }
21
- return [packed, ''];
22
- }
23
- exports.unpackStreamId = unpackStreamId;
24
- function sleep(duration) {
25
- return __awaiter(this, void 0, void 0, function* () {
26
- return new Promise((resolve) => setTimeout(resolve, duration));
27
- });
28
- }
29
- exports.sleep = sleep;
30
- function isFireFox() {
31
- return navigator.userAgent.indexOf('Firefox') !== -1;
32
- }
33
- exports.isFireFox = isFireFox;
34
- function isSafari() {
35
- return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
36
- }
37
- exports.isSafari = isSafari;
38
- function isMobile() {
39
- return /Tablet|iPad|Mobile|Android|BlackBerry/.test(navigator.userAgent);
40
- }
41
- exports.isMobile = isMobile;
42
- function isWeb() {
43
- return typeof document !== 'undefined';
44
- }
45
- exports.isWeb = isWeb;
46
- function roDispatchCallback(entries) {
47
- for (const entry of entries) {
48
- entry.target.handleResize(entry);
49
- }
50
- }
51
- function ioDispatchCallback(entries) {
52
- for (const entry of entries) {
53
- entry.target.handleVisibilityChanged(entry);
54
- }
55
- }
56
- let resizeObserver = null;
57
- const getResizeObserver = () => {
58
- if (!resizeObserver)
59
- resizeObserver = new ResizeObserver(roDispatchCallback);
60
- return resizeObserver;
61
- };
62
- exports.getResizeObserver = getResizeObserver;
63
- let intersectionObserver = null;
64
- const getIntersectionObserver = () => {
65
- if (!intersectionObserver)
66
- intersectionObserver = new IntersectionObserver(ioDispatchCallback);
67
- return intersectionObserver;
68
- };
69
- exports.getIntersectionObserver = getIntersectionObserver;
70
- function getClientInfo() {
71
- const info = livekit_models_1.ClientInfo.fromPartial({
72
- sdk: livekit_models_1.ClientInfo_SDK.JS,
73
- protocol: version_1.protocolVersion,
74
- version: version_1.version,
75
- });
76
- return info;
77
- }
78
- exports.getClientInfo = getClientInfo;
79
- //# sourceMappingURL=utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/room/utils.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,4DAAqE;AACrE,wCAAsD;AAEtD,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB,SAAgB,cAAc,CAAC,MAAc;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACtC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;QACpB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;KACvD;IACD,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACtB,CAAC;AAND,wCAMC;AAED,SAAsB,KAAK,CAAC,QAAgB;;QAC1C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IACjE,CAAC;CAAA;AAFD,sBAEC;AAED,SAAgB,SAAS;IACvB,OAAO,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AACvD,CAAC;AAFD,8BAEC;AAED,SAAgB,QAAQ;IACtB,OAAO,gCAAgC,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AACpE,CAAC;AAFD,4BAEC;AAED,SAAgB,QAAQ;IACtB,OAAO,uCAAuC,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AAC3E,CAAC;AAFD,4BAEC;AAED,SAAgB,KAAK;IACnB,OAAO,OAAO,QAAQ,KAAK,WAAW,CAAC;AACzC,CAAC;AAFD,sBAEC;AAED,SAAS,kBAAkB,CAAC,OAA8B;IACxD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE;QAC1B,KAAK,CAAC,MAAiC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;KAC9D;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAoC;IAC9D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE;QAC1B,KAAK,CAAC,MAAiC,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;KACzE;AACH,CAAC;AAED,IAAI,cAAc,GAA0B,IAAI,CAAC;AAC1C,MAAM,iBAAiB,GAAG,GAAG,EAAE;IACpC,IAAI,CAAC,cAAc;QAAE,cAAc,GAAG,IAAI,cAAc,CAAC,kBAAkB,CAAC,CAAC;IAC7E,OAAO,cAAc,CAAC;AACxB,CAAC,CAAC;AAHW,QAAA,iBAAiB,qBAG5B;AAEF,IAAI,oBAAoB,GAAgC,IAAI,CAAC;AACtD,MAAM,uBAAuB,GAAG,GAAG,EAAE;IAC1C,IAAI,CAAC,oBAAoB;QAAE,oBAAoB,GAAG,IAAI,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;IAC/F,OAAO,oBAAoB,CAAC;AAC9B,CAAC,CAAC;AAHW,QAAA,uBAAuB,2BAGlC;AAOF,SAAgB,aAAa;IAC3B,MAAM,IAAI,GAAG,2BAAU,CAAC,WAAW,CAAC;QAClC,GAAG,EAAE,+BAAc,CAAC,EAAE;QACtB,QAAQ,EAAE,yBAAe;QACzB,OAAO,EAAP,iBAAO;KACR,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC;AAPD,sCAOC"}
package/dist/version.js DELETED
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.protocolVersion = exports.version = void 0;
4
- exports.version = '0.17.4';
5
- exports.protocolVersion = 7;
6
- //# sourceMappingURL=version.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,QAAQ,CAAC;AACnB,QAAA,eAAe,GAAG,CAAC,CAAC"}
package/jest.config.js DELETED
@@ -1,6 +0,0 @@
1
- module.exports = {
2
- clearMocks: true,
3
- modulePathIgnorePatterns: ['<rootDir>/dist/'],
4
- preset: 'ts-jest',
5
- testEnvironment: 'node',
6
- };
@@ -1,53 +0,0 @@
1
- import log from '../logger';
2
-
3
- export default class Queue {
4
- private queue: Array<() => void>;
5
-
6
- private running: boolean;
7
-
8
- constructor() {
9
- this.queue = [];
10
- this.running = false;
11
- }
12
-
13
- enqueue(cb: () => void) {
14
- log.trace('enqueuing request to fire later');
15
- this.queue.push(cb);
16
- }
17
-
18
- dequeue() {
19
- const evt = this.queue.shift();
20
- if (evt) evt();
21
- log.trace('firing request from queue');
22
- }
23
-
24
- async run() {
25
- if (this.running) return;
26
- log.trace('start queue');
27
- this.running = true;
28
- while (this.running && this.queue.length > 0) {
29
- this.dequeue();
30
- }
31
- this.running = false;
32
- log.trace('queue finished');
33
- }
34
-
35
- pause() {
36
- log.trace('pausing queue');
37
- this.running = false;
38
- }
39
-
40
- reset() {
41
- log.trace('resetting queue');
42
- this.running = false;
43
- this.queue = [];
44
- }
45
-
46
- isRunning() {
47
- return this.running;
48
- }
49
-
50
- isEmpty() {
51
- return this.queue.length === 0;
52
- }
53
- }
@@ -1,499 +0,0 @@
1
- import log from '../logger';
2
- import {
3
- ClientInfo,
4
- ParticipantInfo, Room, SpeakerInfo, VideoLayer,
5
- } from '../proto/livekit_models';
6
- import {
7
- AddTrackRequest,
8
- ConnectionQualityUpdate,
9
- JoinResponse,
10
- LeaveRequest,
11
- SessionDescription,
12
- SignalRequest,
13
- SignalResponse,
14
- SignalTarget, SimulateScenario,
15
- StreamStateUpdate,
16
- SubscribedQualityUpdate,
17
- SubscriptionPermissionUpdate, SyncState, TrackPermission,
18
- TrackPublishedResponse,
19
- TrackUnpublishedResponse,
20
- UpdateSubscription, UpdateTrackSettings,
21
- } from '../proto/livekit_rtc';
22
- import { ConnectionError } from '../room/errors';
23
- import { getClientInfo, isWeb, sleep } from '../room/utils';
24
- import Queue from './RequestQueue';
25
-
26
- if (isWeb()) {
27
- import('webrtc-adapter');
28
- }
29
-
30
- // internal options
31
- interface ConnectOpts {
32
- autoSubscribe?: boolean;
33
- /** internal */
34
- reconnect?: boolean;
35
-
36
- publishOnly?: string;
37
- }
38
-
39
- // public options
40
- export interface SignalOptions {
41
- autoSubscribe?: boolean;
42
- publishOnly?: string;
43
- }
44
-
45
- const passThroughQueueSignals: Array<keyof SignalRequest> = [
46
- 'syncState',
47
- 'trickle',
48
- 'offer',
49
- 'answer',
50
- 'simulate',
51
- 'leave',
52
- ];
53
-
54
- function canPassThroughQueue(req: SignalRequest): boolean {
55
- const canPass = Object.keys(req)
56
- .find((key) => passThroughQueueSignals.includes(key as keyof SignalRequest)) !== undefined;
57
- log.trace('request allowed to bypass queue:', canPass, req);
58
- return canPass;
59
- }
60
-
61
- /** @internal */
62
- export class SignalClient {
63
- isConnected: boolean;
64
-
65
- isReconnecting: boolean;
66
-
67
- requestQueue: Queue;
68
-
69
- useJSON: boolean;
70
-
71
- /** simulate signaling latency by delaying messages */
72
- signalLatency?: number;
73
-
74
- onClose?: (reason: string) => void;
75
-
76
- onAnswer?: (sd: RTCSessionDescriptionInit) => void;
77
-
78
- onOffer?: (sd: RTCSessionDescriptionInit) => void;
79
-
80
- // when a new ICE candidate is made available
81
- onTrickle?: (sd: RTCIceCandidateInit, target: SignalTarget) => void;
82
-
83
- onParticipantUpdate?: (updates: ParticipantInfo[]) => void;
84
-
85
- onLocalTrackPublished?: (res: TrackPublishedResponse) => void;
86
-
87
- onNegotiateRequested?: () => void;
88
-
89
- onSpeakersChanged?: (res: SpeakerInfo[]) => void;
90
-
91
- onRemoteMuteChanged?: (trackSid: string, muted: boolean) => void;
92
-
93
- onRoomUpdate?: (room: Room) => void;
94
-
95
- onConnectionQuality?: (update: ConnectionQualityUpdate) => void;
96
-
97
- onStreamStateUpdate?: (update: StreamStateUpdate) => void;
98
-
99
- onSubscribedQualityUpdate?: (update: SubscribedQualityUpdate) => void;
100
-
101
- onSubscriptionPermissionUpdate?: (update: SubscriptionPermissionUpdate) => void;
102
-
103
- onLocalTrackUnpublished?: (res: TrackUnpublishedResponse) => void;
104
-
105
- onTokenRefresh?: (token: string) => void;
106
-
107
- onLeave?: (leave: LeaveRequest) => void;
108
-
109
- ws?: WebSocket;
110
-
111
- constructor(useJSON: boolean = false) {
112
- this.isConnected = false;
113
- this.isReconnecting = false;
114
- this.useJSON = useJSON;
115
- this.requestQueue = new Queue();
116
- }
117
-
118
- async join(
119
- url: string,
120
- token: string,
121
- opts?: SignalOptions,
122
- ): Promise<JoinResponse> {
123
- // during a full reconnect, we'd want to start the sequence even if currently
124
- // connected
125
- this.isConnected = false;
126
- const res = await this.connect(url, token, {
127
- autoSubscribe: opts?.autoSubscribe,
128
- publishOnly: opts?.publishOnly,
129
- });
130
- return res as JoinResponse;
131
- }
132
-
133
- async reconnect(url: string, token: string): Promise<void> {
134
- this.isReconnecting = true;
135
- await this.connect(url, token, {
136
- reconnect: true,
137
- });
138
- }
139
-
140
- connect(
141
- url: string,
142
- token: string,
143
- opts: ConnectOpts,
144
- ): Promise<JoinResponse | void> {
145
- if (url.startsWith('http')) {
146
- url = url.replace('http', 'ws');
147
- }
148
- // strip trailing slash
149
- url = url.replace(/\/$/, '');
150
- url += '/rtc';
151
-
152
- const clientInfo = getClientInfo();
153
- const params = createConnectionParams(token, clientInfo, opts);
154
-
155
- return new Promise<JoinResponse | void>((resolve, reject) => {
156
- log.debug('connecting to', url + params);
157
- this.ws = undefined;
158
- const ws = new WebSocket(url + params);
159
- ws.binaryType = 'arraybuffer';
160
-
161
- ws.onerror = async (ev: Event) => {
162
- if (!this.ws) {
163
- try {
164
- const resp = await fetch(`http${url.substring(2)}/validate${params}`);
165
- if (!resp.ok) {
166
- const msg = await resp.text();
167
- reject(new ConnectionError(msg));
168
- } else {
169
- reject(new ConnectionError('Internal error'));
170
- }
171
- } catch (e) {
172
- reject(new ConnectionError('server was not reachable'));
173
- }
174
- return;
175
- }
176
- // other errors, handle
177
- this.handleWSError(ev);
178
- };
179
-
180
- ws.onopen = () => {
181
- this.ws = ws;
182
- if (opts.reconnect) {
183
- // upon reconnection, there will not be additional handshake
184
- this.isConnected = true;
185
- resolve();
186
- }
187
- };
188
-
189
- ws.onmessage = async (ev: MessageEvent) => {
190
- // not considered connected until JoinResponse is received
191
- let msg: SignalResponse;
192
- if (typeof ev.data === 'string') {
193
- const json = JSON.parse(ev.data);
194
- msg = SignalResponse.fromJSON(json);
195
- } else if (ev.data instanceof ArrayBuffer) {
196
- msg = SignalResponse.decode(new Uint8Array(ev.data));
197
- } else {
198
- log.error('could not decode websocket message', typeof ev.data);
199
- return;
200
- }
201
-
202
- if (!this.isConnected) {
203
- // handle join message only
204
- if (msg.join) {
205
- this.isConnected = true;
206
- resolve(msg.join);
207
- } else {
208
- reject(new ConnectionError('did not receive join response'));
209
- }
210
- return;
211
- }
212
-
213
- if (this.signalLatency) {
214
- await sleep(this.signalLatency);
215
- }
216
- this.handleSignalResponse(msg);
217
- };
218
-
219
- ws.onclose = (ev: CloseEvent) => {
220
- if (!this.isConnected || this.ws !== ws) return;
221
-
222
- log.debug('websocket connection closed', ev.reason);
223
- this.isConnected = false;
224
- if (this.onClose) this.onClose(ev.reason);
225
- if (this.ws === ws) {
226
- this.ws = undefined;
227
- }
228
- };
229
- });
230
- }
231
-
232
- close() {
233
- this.isConnected = false;
234
- if (this.ws) this.ws.onclose = null;
235
- this.ws?.close();
236
- this.ws = undefined;
237
- }
238
-
239
- // initial offer after joining
240
- sendOffer(offer: RTCSessionDescriptionInit) {
241
- log.debug('sending offer', offer);
242
- this.sendRequest({
243
- offer: toProtoSessionDescription(offer),
244
- });
245
- }
246
-
247
- // answer a server-initiated offer
248
- sendAnswer(answer: RTCSessionDescriptionInit) {
249
- log.debug('sending answer');
250
- this.sendRequest({
251
- answer: toProtoSessionDescription(answer),
252
- });
253
- }
254
-
255
- sendIceCandidate(candidate: RTCIceCandidateInit, target: SignalTarget) {
256
- log.trace('sending ice candidate', candidate);
257
- this.sendRequest({
258
- trickle: {
259
- candidateInit: JSON.stringify(candidate),
260
- target,
261
- },
262
- });
263
- }
264
-
265
- sendMuteTrack(trackSid: string, muted: boolean) {
266
- this.sendRequest({
267
- mute: {
268
- sid: trackSid,
269
- muted,
270
- },
271
- });
272
- }
273
-
274
- sendAddTrack(req: AddTrackRequest): void {
275
- this.sendRequest({
276
- addTrack: AddTrackRequest.fromPartial(req),
277
- });
278
- }
279
-
280
- sendUpdateTrackSettings(settings: UpdateTrackSettings) {
281
- this.sendRequest({ trackSetting: settings });
282
- }
283
-
284
- sendUpdateSubscription(sub: UpdateSubscription) {
285
- this.sendRequest({ subscription: sub });
286
- }
287
-
288
- sendSyncState(sync: SyncState) {
289
- this.sendRequest({ syncState: sync });
290
- }
291
-
292
- sendUpdateVideoLayers(trackSid: string, layers: VideoLayer[]) {
293
- this.sendRequest({
294
- updateLayers: {
295
- trackSid,
296
- layers,
297
- },
298
- });
299
- }
300
-
301
- sendUpdateSubscriptionPermissions(
302
- allParticipants: boolean,
303
- trackPermissions: TrackPermission[],
304
- ) {
305
- this.sendRequest({
306
- subscriptionPermission: {
307
- allParticipants,
308
- trackPermissions,
309
- },
310
- });
311
- }
312
-
313
- sendSimulateScenario(scenario: SimulateScenario) {
314
- this.sendRequest({
315
- simulate: scenario,
316
- });
317
- }
318
-
319
- sendLeave() {
320
- this.sendRequest(SignalRequest.fromPartial({ leave: {} }));
321
- }
322
-
323
- async sendRequest(req: SignalRequest, fromQueue: boolean = false) {
324
- // capture all requests while reconnecting and put them in a queue.
325
- // keep order by queueing up new events as long as the queue is not empty
326
- // unless the request originates from the queue, then don't enqueue again
327
- const canQueue = !fromQueue && !canPassThroughQueue(req);
328
- if (canQueue && (this.isReconnecting || (!this.requestQueue.isEmpty()))) {
329
- this.requestQueue.enqueue(() => this.sendRequest(req, true));
330
- return;
331
- }
332
- if (this.signalLatency) {
333
- await sleep(this.signalLatency);
334
- }
335
- if (!this.ws) {
336
- log.error('cannot send signal request before connected');
337
- return;
338
- }
339
-
340
- try {
341
- if (this.useJSON) {
342
- this.ws.send(JSON.stringify(SignalRequest.toJSON(req)));
343
- } else {
344
- this.ws.send(SignalRequest.encode(req).finish());
345
- }
346
- } catch (e) {
347
- log.error('error sending signal message', e);
348
- }
349
- }
350
-
351
- private handleSignalResponse(msg: SignalResponse) {
352
- if (msg.answer) {
353
- const sd = fromProtoSessionDescription(msg.answer);
354
- if (this.onAnswer) {
355
- this.onAnswer(sd);
356
- }
357
- } else if (msg.offer) {
358
- const sd = fromProtoSessionDescription(msg.offer);
359
- if (this.onOffer) {
360
- this.onOffer(sd);
361
- }
362
- } else if (msg.trickle) {
363
- const candidate: RTCIceCandidateInit = JSON.parse(
364
- msg.trickle.candidateInit,
365
- );
366
- if (this.onTrickle) {
367
- this.onTrickle(candidate, msg.trickle.target);
368
- }
369
- } else if (msg.update) {
370
- if (this.onParticipantUpdate) {
371
- this.onParticipantUpdate(msg.update.participants);
372
- }
373
- } else if (msg.trackPublished) {
374
- if (this.onLocalTrackPublished) {
375
- this.onLocalTrackPublished(msg.trackPublished);
376
- }
377
- } else if (msg.speakersChanged) {
378
- if (this.onSpeakersChanged) {
379
- this.onSpeakersChanged(msg.speakersChanged.speakers);
380
- }
381
- } else if (msg.leave) {
382
- if (this.onLeave) {
383
- this.onLeave(msg.leave);
384
- }
385
- } else if (msg.mute) {
386
- if (this.onRemoteMuteChanged) {
387
- this.onRemoteMuteChanged(msg.mute.sid, msg.mute.muted);
388
- }
389
- } else if (msg.roomUpdate) {
390
- if (this.onRoomUpdate) {
391
- this.onRoomUpdate(msg.roomUpdate.room!);
392
- }
393
- } else if (msg.connectionQuality) {
394
- if (this.onConnectionQuality) {
395
- this.onConnectionQuality(msg.connectionQuality);
396
- }
397
- } else if (msg.streamStateUpdate) {
398
- if (this.onStreamStateUpdate) {
399
- this.onStreamStateUpdate(msg.streamStateUpdate);
400
- }
401
- } else if (msg.subscribedQualityUpdate) {
402
- if (this.onSubscribedQualityUpdate) {
403
- this.onSubscribedQualityUpdate(msg.subscribedQualityUpdate);
404
- }
405
- } else if (msg.subscriptionPermissionUpdate) {
406
- if (this.onSubscriptionPermissionUpdate) {
407
- this.onSubscriptionPermissionUpdate(msg.subscriptionPermissionUpdate);
408
- }
409
- } else if (msg.refreshToken) {
410
- if (this.onTokenRefresh) {
411
- this.onTokenRefresh(msg.refreshToken);
412
- }
413
- } else if (msg.trackUnpublished) {
414
- if (this.onLocalTrackUnpublished) {
415
- this.onLocalTrackUnpublished(msg.trackUnpublished);
416
- }
417
- } else {
418
- log.debug('unsupported message', msg);
419
- }
420
- }
421
-
422
- setReconnected() {
423
- this.isReconnecting = false;
424
- this.requestQueue.run();
425
- }
426
-
427
- private handleWSError(ev: Event) {
428
- log.error('websocket error', ev);
429
- }
430
- }
431
-
432
- function fromProtoSessionDescription(
433
- sd: SessionDescription,
434
- ): RTCSessionDescriptionInit {
435
- const rsd: RTCSessionDescriptionInit = {
436
- type: 'offer',
437
- sdp: sd.sdp,
438
- };
439
- switch (sd.type) {
440
- case 'answer':
441
- case 'offer':
442
- case 'pranswer':
443
- case 'rollback':
444
- rsd.type = sd.type;
445
- break;
446
- default:
447
- break;
448
- }
449
- return rsd;
450
- }
451
-
452
- export function toProtoSessionDescription(
453
- rsd: RTCSessionDescription | RTCSessionDescriptionInit,
454
- ): SessionDescription {
455
- const sd: SessionDescription = {
456
- sdp: rsd.sdp!,
457
- type: rsd.type!,
458
- };
459
- return sd;
460
- }
461
-
462
- function createConnectionParams(token: string, info: ClientInfo, opts?: ConnectOpts): string {
463
- const params = new URLSearchParams();
464
- params.set('access_token', token);
465
-
466
- // opts
467
- if (opts?.reconnect) {
468
- params.set('reconnect', '1');
469
- }
470
- if (opts?.autoSubscribe !== undefined) {
471
- params.set('auto_subscribe', opts.autoSubscribe ? '1' : '0');
472
- }
473
-
474
- // ClientInfo
475
- params.set('sdk', 'js');
476
- params.set('version', info.version);
477
- params.set('protocol', info.protocol.toString());
478
- if (info.deviceModel) {
479
- params.set('device_model', info.deviceModel);
480
- }
481
- if (info.os) {
482
- params.set('os', info.os);
483
- }
484
- if (info.osVersion) {
485
- params.set('os_version', info.osVersion);
486
- }
487
- if (info.browser) {
488
- params.set('browser', info.browser);
489
- }
490
- if (info.browserVersion) {
491
- params.set('browser_version', info.browserVersion);
492
- }
493
-
494
- if (opts?.publishOnly !== undefined) {
495
- params.set('publish', opts.publishOnly);
496
- }
497
-
498
- return `?${params.toString()}`;
499
- }