@cloudflare/realtimekit-react-native 1.2.0-staging.3 → 1.2.0-staging.5
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.
- package/RealtimeKitCore.podspec +1 -1
- package/ios/scripts/screenshare_sources.rb +74 -0
- package/lib/commonjs/AudioSampleHandler.js +1 -7
- package/lib/commonjs/AudioSampleHandler.js.map +1 -1
- package/lib/commonjs/BackgroundHandler.js +0 -7
- package/lib/commonjs/BackgroundHandler.js.map +1 -1
- package/lib/commonjs/DeviceInfo.js +0 -4
- package/lib/commonjs/DeviceInfo.js.map +1 -1
- package/lib/commonjs/LocalMediaError.js +0 -4
- package/lib/commonjs/LocalMediaError.js.map +1 -1
- package/lib/commonjs/LocalMediaHandler.js +135 -186
- package/lib/commonjs/LocalMediaHandler.js.map +1 -1
- package/lib/commonjs/LocalMediaInterfaces.js.map +1 -1
- package/lib/commonjs/LocalMediaUtils.js +19 -27
- package/lib/commonjs/LocalMediaUtils.js.map +1 -1
- package/lib/commonjs/NativeAudioManager.js +3 -3
- package/lib/commonjs/NativeAudioManager.js.map +1 -1
- package/lib/commonjs/PermissionHandler.js.map +1 -1
- package/lib/commonjs/ReactContext.js +39 -43
- package/lib/commonjs/ReactContext.js.map +1 -1
- package/lib/commonjs/ReactHooks.js +7 -9
- package/lib/commonjs/ReactHooks.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/utils/crypto.js.map +1 -1
- package/lib/commonjs/utils/version.js +1 -1
- package/lib/commonjs/utils/version.js.map +1 -1
- package/lib/module/AudioSampleHandler.js +3 -7
- package/lib/module/AudioSampleHandler.js.map +1 -1
- package/lib/module/BackgroundHandler.js +2 -7
- package/lib/module/BackgroundHandler.js.map +1 -1
- package/lib/module/DeviceInfo.js +2 -4
- package/lib/module/DeviceInfo.js.map +1 -1
- package/lib/module/LocalMediaError.js +2 -4
- package/lib/module/LocalMediaError.js.map +1 -1
- package/lib/module/LocalMediaHandler.js +135 -186
- package/lib/module/LocalMediaHandler.js.map +1 -1
- package/lib/module/LocalMediaInterfaces.js +1 -1
- package/lib/module/LocalMediaInterfaces.js.map +1 -1
- package/lib/module/LocalMediaUtils.js +21 -27
- package/lib/module/LocalMediaUtils.js.map +1 -1
- package/lib/module/NativeAudioManager.js +5 -3
- package/lib/module/NativeAudioManager.js.map +1 -1
- package/lib/module/PermissionHandler.js +2 -0
- package/lib/module/PermissionHandler.js.map +1 -1
- package/lib/module/ReactContext.js +39 -43
- package/lib/module/ReactContext.js.map +1 -1
- package/lib/module/ReactHooks.js +9 -9
- package/lib/module/ReactHooks.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/crypto.js +2 -0
- package/lib/module/utils/crypto.js.map +1 -1
- package/lib/module/utils/version.js +3 -1
- package/lib/module/utils/version.js.map +1 -1
- package/lib/typescript/AudioSampleHandler.d.ts +1 -0
- package/lib/typescript/AudioSampleHandler.d.ts.map +1 -0
- package/lib/typescript/BackgroundHandler.d.ts +1 -0
- package/lib/typescript/BackgroundHandler.d.ts.map +1 -0
- package/lib/typescript/DeviceInfo.d.ts +1 -0
- package/lib/typescript/DeviceInfo.d.ts.map +1 -0
- package/lib/typescript/LocalMediaError.d.ts +1 -0
- package/lib/typescript/LocalMediaError.d.ts.map +1 -0
- package/lib/typescript/LocalMediaHandler.d.ts +1 -0
- package/lib/typescript/LocalMediaHandler.d.ts.map +1 -0
- package/lib/typescript/LocalMediaInterfaces.d.ts +1 -0
- package/lib/typescript/LocalMediaInterfaces.d.ts.map +1 -0
- package/lib/typescript/LocalMediaUtils.d.ts +1 -0
- package/lib/typescript/LocalMediaUtils.d.ts.map +1 -0
- package/lib/typescript/NativeAudioManager.d.ts +1 -0
- package/lib/typescript/NativeAudioManager.d.ts.map +1 -0
- package/lib/typescript/PermissionHandler.d.ts +1 -0
- package/lib/typescript/PermissionHandler.d.ts.map +1 -0
- package/lib/typescript/ReactContext.d.ts +1 -0
- package/lib/typescript/ReactContext.d.ts.map +1 -0
- package/lib/typescript/ReactHooks.d.ts +1 -0
- package/lib/typescript/ReactHooks.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/utils/crypto.d.ts +1 -0
- package/lib/typescript/utils/crypto.d.ts.map +1 -0
- package/lib/typescript/utils/version.d.ts +2 -1
- package/lib/typescript/utils/version.d.ts.map +1 -0
- package/package.json +3 -3
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
4
|
-
function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
|
|
5
|
-
function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
|
|
6
|
-
function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
|
|
7
|
-
function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
|
|
8
|
-
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
9
3
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
10
4
|
import { EventEmitter } from 'events';
|
|
11
5
|
import LocalMediaUtils from './LocalMediaUtils';
|
|
@@ -31,8 +25,6 @@ let _meetingServiceConfig = {
|
|
|
31
25
|
channelId: 'rtk_meeting',
|
|
32
26
|
channelName: 'Ongoing Meeting'
|
|
33
27
|
};
|
|
34
|
-
|
|
35
|
-
// eslint-disable-next-line no-shadow
|
|
36
28
|
export let MediaEvents = /*#__PURE__*/function (MediaEvents) {
|
|
37
29
|
MediaEvents[MediaEvents["AUDIO_TRACK_CHANGE"] = 0] = "AUDIO_TRACK_CHANGE";
|
|
38
30
|
MediaEvents[MediaEvents["VIDEO_TRACK_CHANGE"] = 1] = "VIDEO_TRACK_CHANGE";
|
|
@@ -48,76 +40,50 @@ function checkIfAudioTrackIsSilent(track) {
|
|
|
48
40
|
//TODO
|
|
49
41
|
return !!track;
|
|
50
42
|
}
|
|
51
|
-
var _localMediaUtils = /*#__PURE__*/new WeakMap();
|
|
52
|
-
var _appState = /*#__PURE__*/new WeakMap();
|
|
53
|
-
var _appStateSubscription = /*#__PURE__*/new WeakMap();
|
|
54
|
-
var _interval = /*#__PURE__*/new WeakMap();
|
|
55
|
-
var _screenShareState = /*#__PURE__*/new WeakMap();
|
|
56
|
-
var _deviceRemovalTimeout = /*#__PURE__*/new WeakMap();
|
|
57
|
-
var _broadcastEmitter = /*#__PURE__*/new WeakMap();
|
|
58
|
-
var _broadcastStartedSubscription = /*#__PURE__*/new WeakMap();
|
|
59
|
-
var _broadcastStoppedSubscription = /*#__PURE__*/new WeakMap();
|
|
60
43
|
export default class LocalMediaHandler extends EventEmitter {
|
|
44
|
+
#localMediaUtils;
|
|
45
|
+
#appState;
|
|
46
|
+
#appStateSubscription;
|
|
47
|
+
#interval;
|
|
48
|
+
#screenShareState;
|
|
49
|
+
_pendingScreenShare = false;
|
|
50
|
+
#deviceRemovalTimeout = null;
|
|
51
|
+
#broadcastEmitter;
|
|
52
|
+
#broadcastStartedSubscription;
|
|
53
|
+
#broadcastStoppedSubscription;
|
|
54
|
+
_handleAppStateChange = nextAppState => {
|
|
55
|
+
const prevAppState = this.#appState;
|
|
56
|
+
this.#appState = nextAppState;
|
|
57
|
+
if (prevAppState.match(/inactive|background/) && nextAppState === 'active') {
|
|
58
|
+
// App returned to foreground — stop the background keep-alive timer
|
|
59
|
+
// and kick the video track to recover the camera feed.
|
|
60
|
+
if (this.#interval !== null) {
|
|
61
|
+
BackgroundTimer.clearInterval(this.#interval);
|
|
62
|
+
this.#interval = null;
|
|
63
|
+
}
|
|
64
|
+
if (this.videoTrack) {
|
|
65
|
+
this.videoTrack.enabled = false;
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
if (this.videoTrack) {
|
|
68
|
+
this.videoTrack.enabled = true;
|
|
69
|
+
}
|
|
70
|
+
}, 100);
|
|
71
|
+
}
|
|
72
|
+
} else if (nextAppState.match(/inactive|background/)) {
|
|
73
|
+
// App moved to background — start a recurring no-op timer to keep the
|
|
74
|
+
// JS thread alive so WebRTC/native events continue to be processed.
|
|
75
|
+
// Clear any existing interval first to avoid accumulation.
|
|
76
|
+
if (this.#interval !== null) {
|
|
77
|
+
BackgroundTimer.clearInterval(this.#interval);
|
|
78
|
+
}
|
|
79
|
+
this.#interval = BackgroundTimer.setInterval(() => {}, 1000);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
61
82
|
constructor(localMediaUtils) {
|
|
62
83
|
super();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
_classPrivateFieldInitSpec(this, _interval, void 0);
|
|
67
|
-
_classPrivateFieldInitSpec(this, _screenShareState, void 0);
|
|
68
|
-
_defineProperty(this, "audioTrack", void 0);
|
|
69
|
-
_defineProperty(this, "rawAudioTrack", void 0);
|
|
70
|
-
_defineProperty(this, "videoTrack", void 0);
|
|
71
|
-
_defineProperty(this, "rawVideoTrack", void 0);
|
|
72
|
-
_defineProperty(this, "screenShareTracks", void 0);
|
|
73
|
-
_defineProperty(this, "audioEnabled", void 0);
|
|
74
|
-
_defineProperty(this, "videoEnabled", void 0);
|
|
75
|
-
_defineProperty(this, "screenShareEnabled", void 0);
|
|
76
|
-
_defineProperty(this, "_pendingScreenShare", false);
|
|
77
|
-
_defineProperty(this, "currentDevices", void 0);
|
|
78
|
-
_defineProperty(this, "permissions", void 0);
|
|
79
|
-
_classPrivateFieldInitSpec(this, _deviceRemovalTimeout, null);
|
|
80
|
-
_classPrivateFieldInitSpec(this, _broadcastEmitter, void 0);
|
|
81
|
-
_classPrivateFieldInitSpec(this, _broadcastStartedSubscription, void 0);
|
|
82
|
-
_classPrivateFieldInitSpec(this, _broadcastStoppedSubscription, void 0);
|
|
83
|
-
_defineProperty(this, "_handleAppStateChange", nextAppState => {
|
|
84
|
-
const prevAppState = _classPrivateFieldGet(_appState, this);
|
|
85
|
-
_classPrivateFieldSet(_appState, this, nextAppState);
|
|
86
|
-
if (prevAppState.match(/inactive|background/) && nextAppState === 'active') {
|
|
87
|
-
// App returned to foreground — stop the background keep-alive timer
|
|
88
|
-
// and kick the video track to recover the camera feed.
|
|
89
|
-
if (_classPrivateFieldGet(_interval, this) !== null) {
|
|
90
|
-
BackgroundTimer.clearInterval(_classPrivateFieldGet(_interval, this));
|
|
91
|
-
_classPrivateFieldSet(_interval, this, null);
|
|
92
|
-
}
|
|
93
|
-
if (this.videoTrack) {
|
|
94
|
-
this.videoTrack.enabled = false;
|
|
95
|
-
setTimeout(() => {
|
|
96
|
-
if (this.videoTrack) {
|
|
97
|
-
this.videoTrack.enabled = true;
|
|
98
|
-
}
|
|
99
|
-
}, 100);
|
|
100
|
-
}
|
|
101
|
-
} else if (nextAppState.match(/inactive|background/)) {
|
|
102
|
-
// App moved to background — start a recurring no-op timer to keep the
|
|
103
|
-
// JS thread alive so WebRTC/native events continue to be processed.
|
|
104
|
-
// Clear any existing interval first to avoid accumulation.
|
|
105
|
-
if (_classPrivateFieldGet(_interval, this) !== null) {
|
|
106
|
-
BackgroundTimer.clearInterval(_classPrivateFieldGet(_interval, this));
|
|
107
|
-
}
|
|
108
|
-
_classPrivateFieldSet(_interval, this, BackgroundTimer.setInterval(() => {}, 1000));
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
// Arrow function so `this` is stable — the same reference is used in both
|
|
112
|
-
// addEventListener (setScreenShareTracks) and removeEventListener
|
|
113
|
-
// (removeScreenShareTracks). A regular method + .bind(this) creates a new
|
|
114
|
-
// function object on every call, making removeEventListener a no-op.
|
|
115
|
-
_defineProperty(this, "onScreenShareEnded", () => {
|
|
116
|
-
this.emit('SCREENSHARE_ENDED');
|
|
117
|
-
});
|
|
118
|
-
_classPrivateFieldSet(_localMediaUtils, this, localMediaUtils);
|
|
119
|
-
_classPrivateFieldSet(_broadcastEmitter, this, broadcastEmitter);
|
|
120
|
-
_classPrivateFieldSet(_appState, this, '');
|
|
84
|
+
this.#localMediaUtils = localMediaUtils;
|
|
85
|
+
this.#broadcastEmitter = broadcastEmitter;
|
|
86
|
+
this.#appState = '';
|
|
121
87
|
this.audioEnabled = true;
|
|
122
88
|
this.videoEnabled = true;
|
|
123
89
|
this.screenShareEnabled = false;
|
|
@@ -135,16 +101,16 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
135
101
|
speaker: undefined
|
|
136
102
|
};
|
|
137
103
|
// LocalMediaUtils onDeviceChange with callback from native onAudioDeviceChanged events
|
|
138
|
-
|
|
104
|
+
this.#localMediaUtils.onDeviceChange(async changedDevices => {
|
|
139
105
|
await this.onDeviceChange(changedDevices, false);
|
|
140
106
|
});
|
|
141
107
|
if (Platform.OS === 'ios') {
|
|
142
|
-
|
|
108
|
+
this.#broadcastStartedSubscription = this.#broadcastEmitter.addListener('iOS_BroadcastStarted', () => {
|
|
143
109
|
this.oniOSBroadcastStart();
|
|
144
|
-
})
|
|
145
|
-
|
|
110
|
+
});
|
|
111
|
+
this.#broadcastStoppedSubscription = this.#broadcastEmitter.addListener('iOS_BroadcastStopped', () => {
|
|
146
112
|
this.oniOSBroadcastStop();
|
|
147
|
-
})
|
|
113
|
+
});
|
|
148
114
|
}
|
|
149
115
|
NativeAudioManager.start({
|
|
150
116
|
media: 'video'
|
|
@@ -154,27 +120,20 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
154
120
|
if (!this.currentDevices.audio || !this.audioEnabled) {
|
|
155
121
|
return;
|
|
156
122
|
}
|
|
157
|
-
await Promise.race([new Promise(resolve => {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
resolve(e);
|
|
161
|
-
});
|
|
162
|
-
}), new Promise(resolve => setTimeout(resolve, 50))]);
|
|
123
|
+
await Promise.race([new Promise(resolve => this.audioTrack?.addEventListener('unmute', e => {
|
|
124
|
+
resolve(e);
|
|
125
|
+
})), new Promise(resolve => setTimeout(resolve, 50))]);
|
|
163
126
|
const reacquireTrack = await this.shouldReacquireTrack('audio');
|
|
164
127
|
if (reacquireTrack) {
|
|
165
|
-
var _this$currentDevices$;
|
|
166
128
|
this.removeMediaStreamTrackListeners(this.audioTrack);
|
|
167
|
-
await this.setupAudioStream(
|
|
129
|
+
await this.setupAudioStream(this.currentDevices.audio?.deviceId);
|
|
168
130
|
this.addMediaStreamTrackListeners(this.audioTrack);
|
|
169
131
|
this.emit('AUDIO_TRACK_CHANGE');
|
|
170
132
|
}
|
|
171
133
|
}
|
|
172
134
|
async conditionallyRestartVideo() {
|
|
173
135
|
if (!this.currentDevices.video || !this.videoEnabled) return;
|
|
174
|
-
await Promise.race([new Promise(resolve =>
|
|
175
|
-
var _this$videoTrack;
|
|
176
|
-
return (_this$videoTrack = this.videoTrack) === null || _this$videoTrack === void 0 ? void 0 : _this$videoTrack.addEventListener('unmute', resolve);
|
|
177
|
-
}), new Promise(resolve => setTimeout(resolve, 50))]);
|
|
136
|
+
await Promise.race([new Promise(resolve => this.videoTrack?.addEventListener('unmute', resolve)), new Promise(resolve => setTimeout(resolve, 50))]);
|
|
178
137
|
const reacquireTrack = await this.shouldReacquireTrack('video');
|
|
179
138
|
if (reacquireTrack) {
|
|
180
139
|
this.removeMediaStreamTrackListeners(this.videoTrack);
|
|
@@ -230,8 +189,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
230
189
|
return mediaStreamTrack;
|
|
231
190
|
}
|
|
232
191
|
async setupAudioStream(deviceId, forceStopTrack = false) {
|
|
233
|
-
|
|
234
|
-
const audioDevices = await _classPrivateFieldGet(_localMediaUtils, this).getAudioDevices();
|
|
192
|
+
const audioDevices = await this.#localMediaUtils.getAudioDevices();
|
|
235
193
|
if (!audioDevices.length) {
|
|
236
194
|
return;
|
|
237
195
|
}
|
|
@@ -239,13 +197,12 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
239
197
|
if (!audioDeviceId) {
|
|
240
198
|
audioDeviceId = (await this.getOperationalMicDeviceId()).deviceId;
|
|
241
199
|
}
|
|
242
|
-
if (
|
|
243
|
-
this.currentDevices.audio =
|
|
200
|
+
if (this.currentDevices.audio?.deviceId !== audioDeviceId) {
|
|
201
|
+
this.currentDevices.audio = this.#localMediaUtils.getDeviceById(audioDeviceId, 'audioinput');
|
|
244
202
|
}
|
|
245
203
|
if (forceStopTrack) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
(_this$rawAudioTrack = this.rawAudioTrack) === null || _this$rawAudioTrack === void 0 || _this$rawAudioTrack.stop();
|
|
204
|
+
this.audioTrack?.stop();
|
|
205
|
+
this.rawAudioTrack?.stop();
|
|
249
206
|
}
|
|
250
207
|
try {
|
|
251
208
|
this.rawAudioTrack = await LocalMediaUtils.getAudioTrack();
|
|
@@ -263,7 +220,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
263
220
|
* So, we need to repopulate the devices once permission is granted.
|
|
264
221
|
*/
|
|
265
222
|
if (this.audioTrack && this.permissions.audio === 'NOT_REQUESTED') {
|
|
266
|
-
await
|
|
223
|
+
await this.#localMediaUtils.repopulateAvailableDevices();
|
|
267
224
|
}
|
|
268
225
|
|
|
269
226
|
// Force update audio devices on iOS after audio session is active
|
|
@@ -277,8 +234,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
277
234
|
// pass
|
|
278
235
|
}
|
|
279
236
|
async setupVideoStream(deviceId, forceStopTrack = false) {
|
|
280
|
-
|
|
281
|
-
const videoDevices = await _classPrivateFieldGet(_localMediaUtils, this).getVideoDevices();
|
|
237
|
+
const videoDevices = await this.#localMediaUtils.getVideoDevices();
|
|
282
238
|
if (!videoDevices.length) {
|
|
283
239
|
return;
|
|
284
240
|
}
|
|
@@ -286,8 +242,8 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
286
242
|
if (!videoDeviceId) {
|
|
287
243
|
videoDeviceId = (await this.getOperationalWebcamDeviceId()).deviceId;
|
|
288
244
|
}
|
|
289
|
-
if (
|
|
290
|
-
this.currentDevices.video =
|
|
245
|
+
if (this.currentDevices.video?.deviceId !== videoDeviceId) {
|
|
246
|
+
this.currentDevices.video = this.#localMediaUtils.getDeviceById(videoDeviceId, 'videoinput');
|
|
291
247
|
}
|
|
292
248
|
|
|
293
249
|
/**
|
|
@@ -311,24 +267,22 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
311
267
|
this.emit('VIDEO_TRACK_CHANGE');
|
|
312
268
|
}
|
|
313
269
|
if (forceStopTrack) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
(_this$rawVideoTrack = this.rawVideoTrack) === null || _this$rawVideoTrack === void 0 || _this$rawVideoTrack.stop();
|
|
270
|
+
this.videoTrack?.stop();
|
|
271
|
+
this.rawVideoTrack?.stop();
|
|
317
272
|
}
|
|
318
273
|
/**
|
|
319
274
|
* NOTE(roerohan): Firefox does not show device labels until permissions are granted.
|
|
320
275
|
* So, we need to repopulate the devices once permission is granted.
|
|
321
276
|
*/
|
|
322
277
|
if (this.videoTrack && this.permissions.video === 'NOT_REQUESTED') {
|
|
323
|
-
await
|
|
278
|
+
await this.#localMediaUtils.repopulateAvailableDevices();
|
|
324
279
|
}
|
|
325
280
|
this.emit('DEVICE_CHANGE', {
|
|
326
281
|
device: this.currentDevices.video
|
|
327
282
|
});
|
|
328
283
|
}
|
|
329
284
|
async setupSpeaker(deviceId) {
|
|
330
|
-
|
|
331
|
-
const speakerDevices = await _classPrivateFieldGet(_localMediaUtils, this).getSpeakerDevices();
|
|
285
|
+
const speakerDevices = await this.#localMediaUtils.getSpeakerDevices();
|
|
332
286
|
if (!speakerDevices.length) {
|
|
333
287
|
return;
|
|
334
288
|
}
|
|
@@ -338,10 +292,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
338
292
|
speakerDeviceId = deviceId;
|
|
339
293
|
} else {
|
|
340
294
|
// Prefer current device if it's still available
|
|
341
|
-
const currentDeviceStillAvailable = speakerDevices.find(d =>
|
|
342
|
-
var _this$currentDevices$4;
|
|
343
|
-
return d.deviceId === ((_this$currentDevices$4 = this.currentDevices.speaker) === null || _this$currentDevices$4 === void 0 ? void 0 : _this$currentDevices$4.deviceId);
|
|
344
|
-
});
|
|
295
|
+
const currentDeviceStillAvailable = speakerDevices.find(d => d.deviceId === this.currentDevices.speaker?.deviceId);
|
|
345
296
|
if (currentDeviceStillAvailable) {
|
|
346
297
|
// Keep current device if it's still connected
|
|
347
298
|
speakerDeviceId = this.currentDevices.speaker.deviceId;
|
|
@@ -350,12 +301,12 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
350
301
|
const bluetoothDevice = speakerDevices.find(d => d.deviceId === 'bluetooth');
|
|
351
302
|
const wiredDevice = speakerDevices.find(d => d.deviceId === 'wired');
|
|
352
303
|
const speakerDevice = speakerDevices.find(d => d.deviceId === 'speaker');
|
|
353
|
-
speakerDeviceId =
|
|
304
|
+
speakerDeviceId = bluetoothDevice?.deviceId ?? wiredDevice?.deviceId ?? speakerDevice?.deviceId ?? speakerDevices[0].deviceId;
|
|
354
305
|
}
|
|
355
306
|
}
|
|
356
|
-
if (
|
|
307
|
+
if (this.currentDevices.speaker?.deviceId !== speakerDeviceId) {
|
|
357
308
|
// Audio Input devices are same as output devices in mobile
|
|
358
|
-
this.currentDevices.audio =
|
|
309
|
+
this.currentDevices.audio = this.#localMediaUtils.getDeviceById(speakerDeviceId, 'audioinput');
|
|
359
310
|
this.currentDevices.speaker = this.currentDevices.audio;
|
|
360
311
|
}
|
|
361
312
|
await this.setDevice(this.currentDevices.audio);
|
|
@@ -364,7 +315,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
364
315
|
});
|
|
365
316
|
}
|
|
366
317
|
async getOperationalWebcamDeviceId() {
|
|
367
|
-
let videoDevices = await
|
|
318
|
+
let videoDevices = await this.#localMediaUtils.getVideoDevices();
|
|
368
319
|
if (!videoDevices.length) {
|
|
369
320
|
return {
|
|
370
321
|
isOperational: false,
|
|
@@ -395,7 +346,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
395
346
|
};
|
|
396
347
|
}
|
|
397
348
|
async getOperationalMicDeviceId() {
|
|
398
|
-
let audioDevices = await
|
|
349
|
+
let audioDevices = await this.#localMediaUtils.getAudioDevices();
|
|
399
350
|
if (!audioDevices.length) {
|
|
400
351
|
return {
|
|
401
352
|
isOperational: false,
|
|
@@ -461,18 +412,18 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
461
412
|
};
|
|
462
413
|
}
|
|
463
414
|
if (audio) {
|
|
464
|
-
const audioDevices = await
|
|
415
|
+
const audioDevices = await this.#localMediaUtils.getAudioDevices();
|
|
465
416
|
if (audioDevices.length !== 0) {
|
|
466
417
|
const audioDeviceId = (await this.getOperationalMicDeviceId()).deviceId;
|
|
467
|
-
this.currentDevices.audio =
|
|
418
|
+
this.currentDevices.audio = this.#localMediaUtils.getDeviceById(audioDeviceId, 'audioinput');
|
|
468
419
|
constraints.audio = true;
|
|
469
420
|
}
|
|
470
421
|
}
|
|
471
422
|
if (video) {
|
|
472
|
-
const videoDevices = await
|
|
423
|
+
const videoDevices = await this.#localMediaUtils.getVideoDevices();
|
|
473
424
|
if (videoDevices.length !== 0) {
|
|
474
425
|
const videoDeviceId = (await this.getOperationalWebcamDeviceId()).deviceId;
|
|
475
|
-
this.currentDevices.video =
|
|
426
|
+
this.currentDevices.video = this.#localMediaUtils.getDeviceById(videoDeviceId, 'videoinput');
|
|
476
427
|
const videoConstraints = LocalMediaUtils.getVideoConstraints({
|
|
477
428
|
videoDeviceId
|
|
478
429
|
});
|
|
@@ -490,7 +441,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
490
441
|
|
|
491
442
|
// Setup Foreground Service after handling permissions
|
|
492
443
|
if (Platform.OS === 'android') {
|
|
493
|
-
|
|
444
|
+
this.#appStateSubscription = AppState.addEventListener('change', this._handleAppStateChange);
|
|
494
445
|
}
|
|
495
446
|
|
|
496
447
|
// Start the meeting foreground service so Android keeps the app alive
|
|
@@ -504,22 +455,19 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
504
455
|
video = true
|
|
505
456
|
} = tracks;
|
|
506
457
|
if (audio) {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
(_this$screenShareTrac2 = this.screenShareTracks) === null || _this$screenShareTrac2 === void 0 || (_this$screenShareTrac2 = _this$screenShareTrac2.audio) === null || _this$screenShareTrac2 === void 0 || _this$screenShareTrac2.release();
|
|
458
|
+
this.screenShareTracks?.audio?.stop();
|
|
459
|
+
this.screenShareTracks?.audio?.release();
|
|
510
460
|
}
|
|
511
461
|
if (video) {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
(_this$screenShareTrac4 = this.screenShareTracks) === null || _this$screenShareTrac4 === void 0 || (_this$screenShareTrac4 = _this$screenShareTrac4.video) === null || _this$screenShareTrac4 === void 0 || _this$screenShareTrac4.release();
|
|
462
|
+
this.screenShareTracks?.video?.stop();
|
|
463
|
+
this.screenShareTracks?.video?.release();
|
|
515
464
|
}
|
|
516
465
|
if (audio && video) {
|
|
517
466
|
this.screenShareEnabled = false;
|
|
518
467
|
}
|
|
519
468
|
}
|
|
520
469
|
removeScreenShareTracks(tracks) {
|
|
521
|
-
|
|
522
|
-
(_this$screenShareTrac5 = this.screenShareTracks.video) === null || _this$screenShareTrac5 === void 0 || _this$screenShareTrac5.removeEventListener('ended', this.onScreenShareEnded);
|
|
470
|
+
this.screenShareTracks.video?.removeEventListener('ended', this.onScreenShareEnded);
|
|
523
471
|
this.stopScreenShareTracks(tracks);
|
|
524
472
|
this.screenShareTracks = {
|
|
525
473
|
audio: undefined,
|
|
@@ -531,9 +479,8 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
531
479
|
return;
|
|
532
480
|
}
|
|
533
481
|
if (audioTrack === undefined) {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
(_this$rawAudioTrack3 = this.rawAudioTrack) === null || _this$rawAudioTrack3 === void 0 || _this$rawAudioTrack3.release();
|
|
482
|
+
this.rawAudioTrack?.stop();
|
|
483
|
+
this.rawAudioTrack?.release();
|
|
537
484
|
this.rawAudioTrack = undefined;
|
|
538
485
|
}
|
|
539
486
|
this.audioTrack = audioTrack;
|
|
@@ -543,15 +490,13 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
543
490
|
return;
|
|
544
491
|
}
|
|
545
492
|
if (videoTrack === undefined) {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
(_this$rawVideoTrack3 = this.rawVideoTrack) === null || _this$rawVideoTrack3 === void 0 || _this$rawVideoTrack3.release();
|
|
493
|
+
this.rawVideoTrack?.stop();
|
|
494
|
+
this.rawVideoTrack?.release();
|
|
549
495
|
this.rawVideoTrack = undefined;
|
|
550
496
|
}
|
|
551
497
|
this.videoTrack = videoTrack;
|
|
552
498
|
}
|
|
553
499
|
setScreenShareTracks(tracks) {
|
|
554
|
-
var _this$screenShareTrac6;
|
|
555
500
|
const {
|
|
556
501
|
audio,
|
|
557
502
|
video
|
|
@@ -563,8 +508,16 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
563
508
|
});
|
|
564
509
|
}
|
|
565
510
|
this.screenShareTracks = tracks;
|
|
566
|
-
|
|
511
|
+
this.screenShareTracks.video?.addEventListener('ended', this.onScreenShareEnded);
|
|
567
512
|
}
|
|
513
|
+
|
|
514
|
+
// Arrow function so `this` is stable — the same reference is used in both
|
|
515
|
+
// addEventListener (setScreenShareTracks) and removeEventListener
|
|
516
|
+
// (removeScreenShareTracks). A regular method + .bind(this) creates a new
|
|
517
|
+
// function object on every call, making removeEventListener a no-op.
|
|
518
|
+
onScreenShareEnded = () => {
|
|
519
|
+
this.emit('SCREENSHARE_ENDED');
|
|
520
|
+
};
|
|
568
521
|
async disableAudio() {
|
|
569
522
|
await this.toggleAudio();
|
|
570
523
|
}
|
|
@@ -597,12 +550,15 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
597
550
|
}
|
|
598
551
|
try {
|
|
599
552
|
/**
|
|
600
|
-
* NOTE
|
|
601
|
-
*
|
|
553
|
+
* NOTE: audioEnabled is set to true BEFORE setupAudioStream so that the
|
|
554
|
+
* AUDIO_TRACK_CHANGE event (emitted inside setupAudioStream) sees the
|
|
555
|
+
* correct enabled state and the Self.ts handler calls shareMic()
|
|
556
|
+
* immediately.
|
|
557
|
+
* If track acquisition fails, audioEnabled is rolled back to false below.
|
|
602
558
|
*/
|
|
559
|
+
this.audioEnabled = true;
|
|
603
560
|
if (!this.audioTrack || this.audioTrack.readyState === 'ended') {
|
|
604
|
-
|
|
605
|
-
await this.setupAudioStream((_this$currentDevices$6 = this.currentDevices.audio) === null || _this$currentDevices$6 === void 0 ? void 0 : _this$currentDevices$6.deviceId);
|
|
561
|
+
await this.setupAudioStream(this.currentDevices.audio?.deviceId);
|
|
606
562
|
}
|
|
607
563
|
// if we still can't get a track after setting up audio stream
|
|
608
564
|
// do not toggle the audio state
|
|
@@ -610,7 +566,6 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
610
566
|
this.audioEnabled = false;
|
|
611
567
|
return;
|
|
612
568
|
}
|
|
613
|
-
this.audioEnabled = true;
|
|
614
569
|
} catch (ex) {
|
|
615
570
|
this.audioEnabled = false;
|
|
616
571
|
this.audioTrack = undefined;
|
|
@@ -627,7 +582,6 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
627
582
|
await this.toggleVideo();
|
|
628
583
|
}
|
|
629
584
|
async toggleVideo() {
|
|
630
|
-
var _this$currentDevices$7;
|
|
631
585
|
if (this.permissions.video !== 'ACCEPTED') {
|
|
632
586
|
try {
|
|
633
587
|
const permResult = await setupPermissions(false, true);
|
|
@@ -645,9 +599,8 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
645
599
|
return;
|
|
646
600
|
}
|
|
647
601
|
if (this.videoEnabled) {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
(_this$rawVideoTrack5 = this.rawVideoTrack) === null || _this$rawVideoTrack5 === void 0 || _this$rawVideoTrack5.release();
|
|
602
|
+
this.rawVideoTrack?.stop();
|
|
603
|
+
this.rawVideoTrack?.release();
|
|
651
604
|
this.rawVideoTrack = undefined;
|
|
652
605
|
this.videoEnabled = false;
|
|
653
606
|
return;
|
|
@@ -657,16 +610,15 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
657
610
|
* hence it must be set to true first.
|
|
658
611
|
*/
|
|
659
612
|
this.videoEnabled = true;
|
|
660
|
-
await this.setupVideoStream(
|
|
613
|
+
await this.setupVideoStream(this.currentDevices.video?.deviceId);
|
|
661
614
|
}
|
|
662
615
|
async setAudioDevice(device) {
|
|
663
616
|
await this.setupAudioStream(device.deviceId);
|
|
664
617
|
}
|
|
665
618
|
async setVideoDevice(device) {
|
|
666
619
|
if (this.videoEnabled) {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
(_this$rawVideoTrack7 = this.rawVideoTrack) === null || _this$rawVideoTrack7 === void 0 || _this$rawVideoTrack7.release();
|
|
620
|
+
this.rawVideoTrack?.stop();
|
|
621
|
+
this.rawVideoTrack?.release();
|
|
670
622
|
this.rawVideoTrack = undefined;
|
|
671
623
|
}
|
|
672
624
|
await this.setupVideoStream(device.deviceId);
|
|
@@ -675,15 +627,15 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
675
627
|
await this.setupSpeaker(device.deviceId);
|
|
676
628
|
}
|
|
677
629
|
async setDevice(route) {
|
|
678
|
-
await
|
|
630
|
+
await this.#localMediaUtils.chooseAudioRoute(route.deviceId);
|
|
679
631
|
}
|
|
680
632
|
async oniOSBroadcastStart() {
|
|
681
633
|
this.setScreenShareTracks(await LocalMediaUtils.getScreenShareTracks());
|
|
682
634
|
this.screenShareEnabled = true;
|
|
683
|
-
|
|
635
|
+
this.#screenShareState = 'STARTED';
|
|
684
636
|
}
|
|
685
637
|
async oniOSBroadcastStop() {
|
|
686
|
-
|
|
638
|
+
this.#screenShareState = 'STOPPED';
|
|
687
639
|
if (this.screenShareEnabled) {
|
|
688
640
|
this.removeScreenShareTracks();
|
|
689
641
|
return;
|
|
@@ -707,13 +659,13 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
707
659
|
}
|
|
708
660
|
}
|
|
709
661
|
if (Platform.OS === 'ios') {
|
|
710
|
-
|
|
662
|
+
this.#screenShareState = 'PENDING';
|
|
711
663
|
NativeModules.RTKScreensharePickerView.showScreenSharePickerView();
|
|
712
664
|
await new Promise((resolve, reject) => {
|
|
713
665
|
let timeoutId;
|
|
714
666
|
let time = 0;
|
|
715
667
|
timeoutId = setInterval(() => {
|
|
716
|
-
if (
|
|
668
|
+
if (this.#screenShareState === 'STARTED') {
|
|
717
669
|
clearInterval(timeoutId);
|
|
718
670
|
resolve();
|
|
719
671
|
}
|
|
@@ -736,12 +688,12 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
736
688
|
|
|
737
689
|
// iOS: trigger the broadcast picker to stop the extension.
|
|
738
690
|
NativeModules.RTKScreensharePickerView.showScreenSharePickerView();
|
|
739
|
-
|
|
691
|
+
this.#screenShareState = 'PENDING';
|
|
740
692
|
await new Promise((resolve, reject) => {
|
|
741
693
|
let timeoutId;
|
|
742
694
|
let time = 0;
|
|
743
695
|
timeoutId = setInterval(() => {
|
|
744
|
-
if (
|
|
696
|
+
if (this.#screenShareState === 'STOPPED') {
|
|
745
697
|
clearInterval(timeoutId);
|
|
746
698
|
resolve();
|
|
747
699
|
}
|
|
@@ -754,22 +706,22 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
754
706
|
});
|
|
755
707
|
}
|
|
756
708
|
getAllDevices() {
|
|
757
|
-
return
|
|
709
|
+
return this.#localMediaUtils.availableDevices;
|
|
758
710
|
}
|
|
759
711
|
getCurrentDevices() {
|
|
760
712
|
return this.currentDevices;
|
|
761
713
|
}
|
|
762
714
|
getDeviceById(deviceId, kind) {
|
|
763
|
-
return
|
|
715
|
+
return this.#localMediaUtils.getDeviceById(deviceId, kind);
|
|
764
716
|
}
|
|
765
717
|
async getAudioDevices() {
|
|
766
|
-
const devices = await
|
|
718
|
+
const devices = await this.#localMediaUtils.getAudioDevices();
|
|
767
719
|
|
|
768
720
|
// Update current audio device from native layer
|
|
769
721
|
try {
|
|
770
722
|
const currentDeviceId = await NativeAudioManager.getCurrentAudioDevice();
|
|
771
723
|
if (currentDeviceId) {
|
|
772
|
-
const currentDevice =
|
|
724
|
+
const currentDevice = this.#localMediaUtils.getDeviceById(currentDeviceId, 'audioinput');
|
|
773
725
|
if (currentDevice) {
|
|
774
726
|
this.currentDevices.audio = currentDevice;
|
|
775
727
|
}
|
|
@@ -780,16 +732,16 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
780
732
|
return devices;
|
|
781
733
|
}
|
|
782
734
|
async getVideoDevices() {
|
|
783
|
-
return await
|
|
735
|
+
return await this.#localMediaUtils.getVideoDevices();
|
|
784
736
|
}
|
|
785
737
|
async getSpeakerDevices() {
|
|
786
|
-
const devices = await
|
|
738
|
+
const devices = await this.#localMediaUtils.getSpeakerDevices();
|
|
787
739
|
|
|
788
740
|
// Update current speaker device from native layer
|
|
789
741
|
try {
|
|
790
742
|
const currentDeviceId = await NativeAudioManager.getCurrentAudioDevice();
|
|
791
743
|
if (currentDeviceId) {
|
|
792
|
-
const currentDevice =
|
|
744
|
+
const currentDevice = this.#localMediaUtils.getDeviceById(currentDeviceId, 'audioinput');
|
|
793
745
|
if (currentDevice) {
|
|
794
746
|
this.currentDevices.speaker = currentDevice;
|
|
795
747
|
this.currentDevices.audio = currentDevice;
|
|
@@ -808,7 +760,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
808
760
|
|
|
809
761
|
// Update currentDevices.speaker when platform reports selected device change
|
|
810
762
|
if (changedDevices.selectedDevice) {
|
|
811
|
-
const selectedDeviceInfo =
|
|
763
|
+
const selectedDeviceInfo = this.#localMediaUtils.getDeviceById(changedDevices.selectedDevice, 'audioinput');
|
|
812
764
|
if (selectedDeviceInfo) {
|
|
813
765
|
this.currentDevices.speaker = selectedDeviceInfo;
|
|
814
766
|
this.currentDevices.audio = selectedDeviceInfo;
|
|
@@ -822,9 +774,9 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
822
774
|
*/
|
|
823
775
|
if (addedDevice) {
|
|
824
776
|
// Clear any pending device removal timeout when a device is added
|
|
825
|
-
if (
|
|
826
|
-
clearTimeout(
|
|
827
|
-
|
|
777
|
+
if (this.#deviceRemovalTimeout) {
|
|
778
|
+
clearTimeout(this.#deviceRemovalTimeout);
|
|
779
|
+
this.#deviceRemovalTimeout = null;
|
|
828
780
|
}
|
|
829
781
|
if (addedDevice.kind === 'audioinput') {
|
|
830
782
|
if (this.permissions.audio === 'DENIED' || this.permissions.audio === 'NOT_REQUESTED') {
|
|
@@ -862,7 +814,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
862
814
|
};
|
|
863
815
|
if (isBluetoothRemoved) {
|
|
864
816
|
// Wait 500ms before switching away from Bluetooth to allow for reconnection
|
|
865
|
-
|
|
817
|
+
this.#deviceRemovalTimeout = setTimeout(handleRemoval, 500);
|
|
866
818
|
} else {
|
|
867
819
|
// For other devices, handle removal immediately
|
|
868
820
|
await handleRemoval();
|
|
@@ -924,28 +876,25 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
924
876
|
return super.on(event, listener);
|
|
925
877
|
}
|
|
926
878
|
destruct() {
|
|
927
|
-
var _classPrivateFieldGet2;
|
|
928
879
|
this.stopAudioTrack();
|
|
929
880
|
this.stopVideoTrack();
|
|
930
881
|
this.stopScreenShareTracks();
|
|
931
|
-
if (Platform.OS === 'android')
|
|
882
|
+
if (Platform.OS === 'android') this.#appStateSubscription?.remove();
|
|
932
883
|
}
|
|
933
884
|
stopAudioTrack() {
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
(_this$audioTrack4 = this.audioTrack) === null || _this$audioTrack4 === void 0 || _this$audioTrack4.release();
|
|
885
|
+
this.rawAudioTrack?.stop();
|
|
886
|
+
this.audioTrack?.stop();
|
|
887
|
+
this.rawAudioTrack?.release();
|
|
888
|
+
this.audioTrack?.release();
|
|
939
889
|
this.audioEnabled = false;
|
|
940
890
|
this.audioTrack = undefined;
|
|
941
891
|
this.rawAudioTrack = undefined;
|
|
942
892
|
}
|
|
943
893
|
stopVideoTrack() {
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
(_this$videoTrack4 = this.videoTrack) === null || _this$videoTrack4 === void 0 || _this$videoTrack4.release();
|
|
894
|
+
this.rawVideoTrack?.stop();
|
|
895
|
+
this.videoTrack?.stop();
|
|
896
|
+
this.rawVideoTrack?.release();
|
|
897
|
+
this.videoTrack?.release();
|
|
949
898
|
this.videoTrack = undefined;
|
|
950
899
|
this.rawVideoTrack = undefined;
|
|
951
900
|
}
|