@cloudflare/realtimekit-react-native 1.2.0-staging.4 → 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 +129 -183
- 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 +129 -183
- 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
|
}
|
|
@@ -605,8 +558,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
605
558
|
*/
|
|
606
559
|
this.audioEnabled = true;
|
|
607
560
|
if (!this.audioTrack || this.audioTrack.readyState === 'ended') {
|
|
608
|
-
|
|
609
|
-
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);
|
|
610
562
|
}
|
|
611
563
|
// if we still can't get a track after setting up audio stream
|
|
612
564
|
// do not toggle the audio state
|
|
@@ -630,7 +582,6 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
630
582
|
await this.toggleVideo();
|
|
631
583
|
}
|
|
632
584
|
async toggleVideo() {
|
|
633
|
-
var _this$currentDevices$7;
|
|
634
585
|
if (this.permissions.video !== 'ACCEPTED') {
|
|
635
586
|
try {
|
|
636
587
|
const permResult = await setupPermissions(false, true);
|
|
@@ -648,9 +599,8 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
648
599
|
return;
|
|
649
600
|
}
|
|
650
601
|
if (this.videoEnabled) {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
(_this$rawVideoTrack5 = this.rawVideoTrack) === null || _this$rawVideoTrack5 === void 0 || _this$rawVideoTrack5.release();
|
|
602
|
+
this.rawVideoTrack?.stop();
|
|
603
|
+
this.rawVideoTrack?.release();
|
|
654
604
|
this.rawVideoTrack = undefined;
|
|
655
605
|
this.videoEnabled = false;
|
|
656
606
|
return;
|
|
@@ -660,16 +610,15 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
660
610
|
* hence it must be set to true first.
|
|
661
611
|
*/
|
|
662
612
|
this.videoEnabled = true;
|
|
663
|
-
await this.setupVideoStream(
|
|
613
|
+
await this.setupVideoStream(this.currentDevices.video?.deviceId);
|
|
664
614
|
}
|
|
665
615
|
async setAudioDevice(device) {
|
|
666
616
|
await this.setupAudioStream(device.deviceId);
|
|
667
617
|
}
|
|
668
618
|
async setVideoDevice(device) {
|
|
669
619
|
if (this.videoEnabled) {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
(_this$rawVideoTrack7 = this.rawVideoTrack) === null || _this$rawVideoTrack7 === void 0 || _this$rawVideoTrack7.release();
|
|
620
|
+
this.rawVideoTrack?.stop();
|
|
621
|
+
this.rawVideoTrack?.release();
|
|
673
622
|
this.rawVideoTrack = undefined;
|
|
674
623
|
}
|
|
675
624
|
await this.setupVideoStream(device.deviceId);
|
|
@@ -678,15 +627,15 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
678
627
|
await this.setupSpeaker(device.deviceId);
|
|
679
628
|
}
|
|
680
629
|
async setDevice(route) {
|
|
681
|
-
await
|
|
630
|
+
await this.#localMediaUtils.chooseAudioRoute(route.deviceId);
|
|
682
631
|
}
|
|
683
632
|
async oniOSBroadcastStart() {
|
|
684
633
|
this.setScreenShareTracks(await LocalMediaUtils.getScreenShareTracks());
|
|
685
634
|
this.screenShareEnabled = true;
|
|
686
|
-
|
|
635
|
+
this.#screenShareState = 'STARTED';
|
|
687
636
|
}
|
|
688
637
|
async oniOSBroadcastStop() {
|
|
689
|
-
|
|
638
|
+
this.#screenShareState = 'STOPPED';
|
|
690
639
|
if (this.screenShareEnabled) {
|
|
691
640
|
this.removeScreenShareTracks();
|
|
692
641
|
return;
|
|
@@ -710,13 +659,13 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
710
659
|
}
|
|
711
660
|
}
|
|
712
661
|
if (Platform.OS === 'ios') {
|
|
713
|
-
|
|
662
|
+
this.#screenShareState = 'PENDING';
|
|
714
663
|
NativeModules.RTKScreensharePickerView.showScreenSharePickerView();
|
|
715
664
|
await new Promise((resolve, reject) => {
|
|
716
665
|
let timeoutId;
|
|
717
666
|
let time = 0;
|
|
718
667
|
timeoutId = setInterval(() => {
|
|
719
|
-
if (
|
|
668
|
+
if (this.#screenShareState === 'STARTED') {
|
|
720
669
|
clearInterval(timeoutId);
|
|
721
670
|
resolve();
|
|
722
671
|
}
|
|
@@ -739,12 +688,12 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
739
688
|
|
|
740
689
|
// iOS: trigger the broadcast picker to stop the extension.
|
|
741
690
|
NativeModules.RTKScreensharePickerView.showScreenSharePickerView();
|
|
742
|
-
|
|
691
|
+
this.#screenShareState = 'PENDING';
|
|
743
692
|
await new Promise((resolve, reject) => {
|
|
744
693
|
let timeoutId;
|
|
745
694
|
let time = 0;
|
|
746
695
|
timeoutId = setInterval(() => {
|
|
747
|
-
if (
|
|
696
|
+
if (this.#screenShareState === 'STOPPED') {
|
|
748
697
|
clearInterval(timeoutId);
|
|
749
698
|
resolve();
|
|
750
699
|
}
|
|
@@ -757,22 +706,22 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
757
706
|
});
|
|
758
707
|
}
|
|
759
708
|
getAllDevices() {
|
|
760
|
-
return
|
|
709
|
+
return this.#localMediaUtils.availableDevices;
|
|
761
710
|
}
|
|
762
711
|
getCurrentDevices() {
|
|
763
712
|
return this.currentDevices;
|
|
764
713
|
}
|
|
765
714
|
getDeviceById(deviceId, kind) {
|
|
766
|
-
return
|
|
715
|
+
return this.#localMediaUtils.getDeviceById(deviceId, kind);
|
|
767
716
|
}
|
|
768
717
|
async getAudioDevices() {
|
|
769
|
-
const devices = await
|
|
718
|
+
const devices = await this.#localMediaUtils.getAudioDevices();
|
|
770
719
|
|
|
771
720
|
// Update current audio device from native layer
|
|
772
721
|
try {
|
|
773
722
|
const currentDeviceId = await NativeAudioManager.getCurrentAudioDevice();
|
|
774
723
|
if (currentDeviceId) {
|
|
775
|
-
const currentDevice =
|
|
724
|
+
const currentDevice = this.#localMediaUtils.getDeviceById(currentDeviceId, 'audioinput');
|
|
776
725
|
if (currentDevice) {
|
|
777
726
|
this.currentDevices.audio = currentDevice;
|
|
778
727
|
}
|
|
@@ -783,16 +732,16 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
783
732
|
return devices;
|
|
784
733
|
}
|
|
785
734
|
async getVideoDevices() {
|
|
786
|
-
return await
|
|
735
|
+
return await this.#localMediaUtils.getVideoDevices();
|
|
787
736
|
}
|
|
788
737
|
async getSpeakerDevices() {
|
|
789
|
-
const devices = await
|
|
738
|
+
const devices = await this.#localMediaUtils.getSpeakerDevices();
|
|
790
739
|
|
|
791
740
|
// Update current speaker device from native layer
|
|
792
741
|
try {
|
|
793
742
|
const currentDeviceId = await NativeAudioManager.getCurrentAudioDevice();
|
|
794
743
|
if (currentDeviceId) {
|
|
795
|
-
const currentDevice =
|
|
744
|
+
const currentDevice = this.#localMediaUtils.getDeviceById(currentDeviceId, 'audioinput');
|
|
796
745
|
if (currentDevice) {
|
|
797
746
|
this.currentDevices.speaker = currentDevice;
|
|
798
747
|
this.currentDevices.audio = currentDevice;
|
|
@@ -811,7 +760,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
811
760
|
|
|
812
761
|
// Update currentDevices.speaker when platform reports selected device change
|
|
813
762
|
if (changedDevices.selectedDevice) {
|
|
814
|
-
const selectedDeviceInfo =
|
|
763
|
+
const selectedDeviceInfo = this.#localMediaUtils.getDeviceById(changedDevices.selectedDevice, 'audioinput');
|
|
815
764
|
if (selectedDeviceInfo) {
|
|
816
765
|
this.currentDevices.speaker = selectedDeviceInfo;
|
|
817
766
|
this.currentDevices.audio = selectedDeviceInfo;
|
|
@@ -825,9 +774,9 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
825
774
|
*/
|
|
826
775
|
if (addedDevice) {
|
|
827
776
|
// Clear any pending device removal timeout when a device is added
|
|
828
|
-
if (
|
|
829
|
-
clearTimeout(
|
|
830
|
-
|
|
777
|
+
if (this.#deviceRemovalTimeout) {
|
|
778
|
+
clearTimeout(this.#deviceRemovalTimeout);
|
|
779
|
+
this.#deviceRemovalTimeout = null;
|
|
831
780
|
}
|
|
832
781
|
if (addedDevice.kind === 'audioinput') {
|
|
833
782
|
if (this.permissions.audio === 'DENIED' || this.permissions.audio === 'NOT_REQUESTED') {
|
|
@@ -865,7 +814,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
865
814
|
};
|
|
866
815
|
if (isBluetoothRemoved) {
|
|
867
816
|
// Wait 500ms before switching away from Bluetooth to allow for reconnection
|
|
868
|
-
|
|
817
|
+
this.#deviceRemovalTimeout = setTimeout(handleRemoval, 500);
|
|
869
818
|
} else {
|
|
870
819
|
// For other devices, handle removal immediately
|
|
871
820
|
await handleRemoval();
|
|
@@ -927,28 +876,25 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
927
876
|
return super.on(event, listener);
|
|
928
877
|
}
|
|
929
878
|
destruct() {
|
|
930
|
-
var _classPrivateFieldGet2;
|
|
931
879
|
this.stopAudioTrack();
|
|
932
880
|
this.stopVideoTrack();
|
|
933
881
|
this.stopScreenShareTracks();
|
|
934
|
-
if (Platform.OS === 'android')
|
|
882
|
+
if (Platform.OS === 'android') this.#appStateSubscription?.remove();
|
|
935
883
|
}
|
|
936
884
|
stopAudioTrack() {
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
(_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();
|
|
942
889
|
this.audioEnabled = false;
|
|
943
890
|
this.audioTrack = undefined;
|
|
944
891
|
this.rawAudioTrack = undefined;
|
|
945
892
|
}
|
|
946
893
|
stopVideoTrack() {
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
(_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();
|
|
952
898
|
this.videoTrack = undefined;
|
|
953
899
|
this.rawVideoTrack = undefined;
|
|
954
900
|
}
|