@cloudflare/realtimekit-react-native 0.1.4-staging.1 → 0.1.4-staging.3

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 (89) hide show
  1. package/lib/commonjs/AudioSampleHandler.js +61 -0
  2. package/lib/commonjs/AudioSampleHandler.js.map +1 -0
  3. package/lib/commonjs/BackgroundHandler.js +109 -0
  4. package/lib/commonjs/BackgroundHandler.js.map +1 -0
  5. package/lib/commonjs/DeviceInfo.js +37 -0
  6. package/lib/commonjs/DeviceInfo.js.map +1 -0
  7. package/lib/commonjs/LocalMediaError.js +18 -0
  8. package/lib/commonjs/LocalMediaError.js.map +1 -0
  9. package/lib/commonjs/LocalMediaHandler.js +785 -0
  10. package/lib/commonjs/LocalMediaHandler.js.map +1 -0
  11. package/lib/commonjs/LocalMediaInterfaces.js +2 -0
  12. package/lib/commonjs/LocalMediaInterfaces.js.map +1 -0
  13. package/lib/commonjs/LocalMediaUtils.js +298 -0
  14. package/lib/commonjs/LocalMediaUtils.js.map +1 -0
  15. package/lib/commonjs/NativeAudioManager.js +72 -0
  16. package/lib/commonjs/NativeAudioManager.js.map +1 -0
  17. package/lib/commonjs/PermissionHandler.js +157 -0
  18. package/lib/commonjs/PermissionHandler.js.map +1 -0
  19. package/lib/commonjs/ReactContext.js +116 -0
  20. package/lib/commonjs/ReactContext.js.map +1 -0
  21. package/lib/commonjs/ReactHooks.js +99 -0
  22. package/lib/commonjs/ReactHooks.js.map +1 -0
  23. package/lib/commonjs/index.js +95 -0
  24. package/lib/commonjs/index.js.map +1 -0
  25. package/lib/commonjs/utils/constants.js +7 -0
  26. package/lib/commonjs/utils/constants.js.map +1 -0
  27. package/lib/commonjs/utils/crypto.js +76 -0
  28. package/lib/commonjs/utils/crypto.js.map +1 -0
  29. package/lib/commonjs/utils/version.js +8 -0
  30. package/lib/commonjs/utils/version.js.map +1 -0
  31. package/lib/module/AudioSampleHandler.js +54 -0
  32. package/lib/module/AudioSampleHandler.js.map +1 -0
  33. package/lib/module/BackgroundHandler.js +103 -0
  34. package/lib/module/BackgroundHandler.js.map +1 -0
  35. package/lib/module/DeviceInfo.js +31 -0
  36. package/lib/module/DeviceInfo.js.map +1 -0
  37. package/lib/module/LocalMediaError.js +11 -0
  38. package/lib/module/LocalMediaError.js.map +1 -0
  39. package/lib/module/LocalMediaHandler.js +778 -0
  40. package/lib/module/LocalMediaHandler.js.map +1 -0
  41. package/lib/module/LocalMediaInterfaces.js +2 -0
  42. package/lib/module/LocalMediaInterfaces.js.map +1 -0
  43. package/lib/module/LocalMediaUtils.js +290 -0
  44. package/lib/module/LocalMediaUtils.js.map +1 -0
  45. package/lib/module/NativeAudioManager.js +65 -0
  46. package/lib/module/NativeAudioManager.js.map +1 -0
  47. package/lib/module/PermissionHandler.js +149 -0
  48. package/lib/module/PermissionHandler.js.map +1 -0
  49. package/lib/module/ReactContext.js +107 -0
  50. package/lib/module/ReactContext.js.map +1 -0
  51. package/lib/module/ReactHooks.js +75 -0
  52. package/lib/module/ReactHooks.js.map +1 -0
  53. package/lib/{src → module}/index.js +32 -32
  54. package/lib/module/index.js.map +1 -0
  55. package/lib/module/utils/constants.js +5 -0
  56. package/lib/module/utils/constants.js.map +1 -0
  57. package/lib/module/utils/crypto.js +74 -0
  58. package/lib/module/utils/crypto.js.map +1 -0
  59. package/lib/module/utils/version.js +2 -0
  60. package/lib/module/utils/version.js.map +1 -0
  61. package/lib/{src → typescript}/LocalMediaHandler.d.ts +0 -4
  62. package/lib/typescript/utils/constants.d.ts +1 -0
  63. package/lib/typescript/utils/version.d.ts +1 -0
  64. package/package.json +5 -4
  65. package/lib/package.json +0 -168
  66. package/lib/src/AudioSampleHandler.js +0 -57
  67. package/lib/src/BackgroundHandler.js +0 -100
  68. package/lib/src/DeviceInfo.js +0 -27
  69. package/lib/src/LocalMediaError.js +0 -6
  70. package/lib/src/LocalMediaHandler.js +0 -860
  71. package/lib/src/LocalMediaInterfaces.js +0 -1
  72. package/lib/src/LocalMediaUtils.js +0 -288
  73. package/lib/src/NativeAudioManager.js +0 -93
  74. package/lib/src/PermissionHandler.js +0 -179
  75. package/lib/src/ReactContext.js +0 -90
  76. package/lib/src/ReactHooks.js +0 -80
  77. package/lib/src/utils/crypto.js +0 -82
  78. /package/lib/{src → typescript}/AudioSampleHandler.d.ts +0 -0
  79. /package/lib/{src → typescript}/BackgroundHandler.d.ts +0 -0
  80. /package/lib/{src → typescript}/DeviceInfo.d.ts +0 -0
  81. /package/lib/{src → typescript}/LocalMediaError.d.ts +0 -0
  82. /package/lib/{src → typescript}/LocalMediaInterfaces.d.ts +0 -0
  83. /package/lib/{src → typescript}/LocalMediaUtils.d.ts +0 -0
  84. /package/lib/{src → typescript}/NativeAudioManager.d.ts +0 -0
  85. /package/lib/{src → typescript}/PermissionHandler.d.ts +0 -0
  86. /package/lib/{src → typescript}/ReactContext.d.ts +0 -0
  87. /package/lib/{src → typescript}/ReactHooks.d.ts +0 -0
  88. /package/lib/{src → typescript}/index.d.ts +0 -0
  89. /package/lib/{src → typescript}/utils/crypto.d.ts +0 -0
@@ -0,0 +1,785 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.MediaEvents = void 0;
7
+ var _events = require("events");
8
+ var _LocalMediaUtils = _interopRequireDefault(require("./LocalMediaUtils"));
9
+ var _reactNative = require("react-native");
10
+ var _BackgroundHandler = _interopRequireDefault(require("./BackgroundHandler"));
11
+ var _NativeAudioManager = _interopRequireDefault(require("./NativeAudioManager"));
12
+ var _PermissionHandler = require("./PermissionHandler");
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
15
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
16
+ 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); }
17
+ function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
18
+ function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
19
+ function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
20
+ function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
21
+ 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"); } /* eslint-disable @typescript-eslint/no-unused-vars */
22
+ const {
23
+ RTKHelper,
24
+ BroadcastEventEmitter
25
+ } = _reactNative.NativeModules;
26
+ const broadcastEmitter = new _reactNative.NativeEventEmitter(BroadcastEventEmitter);
27
+
28
+ // eslint-disable-next-line no-shadow
29
+ let MediaEvents = exports.MediaEvents = /*#__PURE__*/function (MediaEvents) {
30
+ MediaEvents[MediaEvents["AUDIO_TRACK_CHANGE"] = 0] = "AUDIO_TRACK_CHANGE";
31
+ MediaEvents[MediaEvents["VIDEO_TRACK_CHANGE"] = 1] = "VIDEO_TRACK_CHANGE";
32
+ MediaEvents[MediaEvents["SCREENSHARE_TRACK_CHANGE"] = 2] = "SCREENSHARE_TRACK_CHANGE";
33
+ MediaEvents[MediaEvents["SCREENSHARE_ENDED"] = 3] = "SCREENSHARE_ENDED";
34
+ MediaEvents[MediaEvents["DEVICE_CHANGE"] = 4] = "DEVICE_CHANGE";
35
+ MediaEvents[MediaEvents["SCREENSHARE_STARTED"] = 5] = "SCREENSHARE_STARTED";
36
+ MediaEvents[MediaEvents["MEDIA_PERMISSION_UPDATE"] = 6] = "MEDIA_PERMISSION_UPDATE";
37
+ MediaEvents[MediaEvents["DEVICE_LIST_UPDATED"] = 7] = "DEVICE_LIST_UPDATED";
38
+ return MediaEvents;
39
+ }({});
40
+ function checkIfAudioTrackIsSilent(track) {
41
+ //TODO
42
+ return !!track;
43
+ }
44
+ var _localMediaUtils = /*#__PURE__*/new WeakMap();
45
+ var _appState = /*#__PURE__*/new WeakMap();
46
+ var _appStateSubscription = /*#__PURE__*/new WeakMap();
47
+ var _interval = /*#__PURE__*/new WeakMap();
48
+ class LocalMediaHandler extends _events.EventEmitter {
49
+ async configureForeground() {
50
+ if (_reactNative.Platform.OS !== 'android') return;
51
+ const val = await RTKHelper.isForegroundServiceRunning();
52
+ if (!val) {
53
+ if (_reactNative.Platform.Version >= 33) {
54
+ const res = await _reactNative.PermissionsAndroid.request(_reactNative.PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);
55
+ if (res !== _reactNative.PermissionsAndroid.RESULTS.GRANTED) {
56
+ console.warn('Permission required for screenshare notification');
57
+ }
58
+ }
59
+ if (_reactNative.Platform.Version >= 26) {
60
+ await RTKHelper.createNotificationChannel();
61
+ }
62
+ try {
63
+ await RTKHelper.startService();
64
+ } catch (e) {
65
+ console.warn('Failed to start foreground service', e);
66
+ }
67
+ }
68
+ }
69
+ constructor(localMediaUtils) {
70
+ super();
71
+ _classPrivateFieldInitSpec(this, _localMediaUtils, void 0);
72
+ _classPrivateFieldInitSpec(this, _appState, void 0);
73
+ _classPrivateFieldInitSpec(this, _appStateSubscription, void 0);
74
+ _classPrivateFieldInitSpec(this, _interval, void 0);
75
+ _defineProperty(this, "audioTrack", void 0);
76
+ _defineProperty(this, "rawAudioTrack", void 0);
77
+ _defineProperty(this, "videoTrack", void 0);
78
+ _defineProperty(this, "rawVideoTrack", void 0);
79
+ _defineProperty(this, "screenShareTracks", void 0);
80
+ _defineProperty(this, "audioEnabled", void 0);
81
+ _defineProperty(this, "videoEnabled", void 0);
82
+ _defineProperty(this, "screenShareEnabled", void 0);
83
+ _defineProperty(this, "_pendingScreenShare", false);
84
+ _defineProperty(this, "currentDevices", void 0);
85
+ _defineProperty(this, "permissions", void 0);
86
+ _defineProperty(this, "_handleAppStateChange", nextAppState => {
87
+ if (_classPrivateFieldGet(_appState, this).match(/inactive|background/) && nextAppState === 'active') {
88
+ _BackgroundHandler.default.clearInterval(_classPrivateFieldGet(_interval, this));
89
+ _classPrivateFieldSet(_interval, this, null);
90
+ if (this.videoTrack) {
91
+ this.videoTrack.enabled = false;
92
+ setTimeout(() => {
93
+ if (this.videoTrack) {
94
+ this.videoTrack.enabled = true;
95
+ }
96
+ }, 100);
97
+ }
98
+ } else {
99
+ if (_classPrivateFieldGet(_interval, this) === null) {
100
+ if (this.screenShareEnabled || this._pendingScreenShare) {
101
+ this.configureForeground();
102
+ }
103
+ }
104
+ _classPrivateFieldSet(_interval, this, _BackgroundHandler.default.setInterval(() => {}, 1000));
105
+ _classPrivateFieldSet(_appState, this, nextAppState);
106
+ }
107
+ });
108
+ _classPrivateFieldSet(_localMediaUtils, this, localMediaUtils);
109
+ _classPrivateFieldSet(_appState, this, '');
110
+ this.audioEnabled = true;
111
+ this.videoEnabled = true;
112
+ this.screenShareEnabled = false;
113
+ this.permissions = {
114
+ audio: 'NOT_REQUESTED',
115
+ video: 'NOT_REQUESTED'
116
+ };
117
+ this.screenShareTracks = {
118
+ audio: undefined,
119
+ video: undefined
120
+ };
121
+ this.currentDevices = {
122
+ audio: undefined,
123
+ video: undefined,
124
+ speaker: undefined
125
+ };
126
+ // LocalMediaUtils onDeviceChange with callback from native onAudioDeviceChanged events
127
+ _classPrivateFieldGet(_localMediaUtils, this).onDeviceChange(async changedDevices => {
128
+ await this.onDeviceChange(changedDevices, false);
129
+ });
130
+ if (_reactNative.Platform.OS === 'ios') {
131
+ broadcastEmitter.addListener('iOS_BroadcastStarted', () => {
132
+ this.oniOSBroadcastStart();
133
+ });
134
+ broadcastEmitter.addListener('iOS_BroadcastStopped', () => {
135
+ this.oniOSBroadcastStop();
136
+ });
137
+ }
138
+ _NativeAudioManager.default.start({});
139
+ }
140
+ async conditionallyRestartAudio() {
141
+ if (!this.currentDevices.audio || !this.audioEnabled) {
142
+ return;
143
+ }
144
+ // log.info('maybe_restart_audio: ');
145
+ await Promise.race([new Promise(resolve => {
146
+ var _this$audioTrack;
147
+ return (_this$audioTrack = this.audioTrack) === null || _this$audioTrack === void 0 ? void 0 : _this$audioTrack.addEventListener('unmute', e => {
148
+ resolve(e);
149
+ });
150
+ }), new Promise(resolve => setTimeout(resolve, 50))]);
151
+ const reacquireTrack = await this.shouldReacquireTrack('audio');
152
+ if (reacquireTrack) {
153
+ var _this$currentDevices$;
154
+ this.removeMediaStreamTrackListeners(this.audioTrack);
155
+ await this.setupAudioStream((_this$currentDevices$ = this.currentDevices.audio) === null || _this$currentDevices$ === void 0 ? void 0 : _this$currentDevices$.deviceId);
156
+ this.addMediaStreamTrackListeners(this.audioTrack);
157
+ this.emit('AUDIO_TRACK_CHANGE');
158
+ }
159
+ }
160
+ async conditionallyRestartVideo() {
161
+ if (!this.currentDevices.video || !this.videoEnabled) return;
162
+ // log.info('maybe_restart_video');
163
+
164
+ await Promise.race([new Promise(resolve => {
165
+ var _this$videoTrack;
166
+ return (_this$videoTrack = this.videoTrack) === null || _this$videoTrack === void 0 ? void 0 : _this$videoTrack.addEventListener('unmute', resolve);
167
+ }), new Promise(resolve => setTimeout(resolve, 50))]);
168
+ const reacquireTrack = await this.shouldReacquireTrack('video');
169
+ if (reacquireTrack) {
170
+ this.removeMediaStreamTrackListeners(this.videoTrack);
171
+ await this.setupVideoStream(this.currentDevices.video.deviceId);
172
+ this.addMediaStreamTrackListeners(this.videoTrack);
173
+ this.emit('VIDEO_TRACK_CHANGE');
174
+ }
175
+ }
176
+ async shouldReacquireTrack(kind) {
177
+ const workaroundWebKitBug1208516 = false;
178
+ let mediaStreamTrack;
179
+ let wasEnabled = false;
180
+ if (kind === 'audio') {
181
+ mediaStreamTrack = this.audioTrack;
182
+ wasEnabled = this.audioEnabled;
183
+ } else if (kind === 'video') {
184
+ mediaStreamTrack = this.videoTrack;
185
+ wasEnabled = this.videoEnabled;
186
+ }
187
+ if (!mediaStreamTrack) return false;
188
+ if (!this.rawAudioTrack || !this.audioTrack) return true;
189
+ if (!this.rawVideoTrack || !this.videoTrack) return true;
190
+ const isStopped = mediaStreamTrack.readyState === 'ended';
191
+ const isInadvertentlyStopped = isStopped && wasEnabled && workaroundWebKitBug1208516;
192
+ let isSilentAudio = false;
193
+ if (kind === 'audio') {
194
+ isSilentAudio = await checkIfAudioTrackIsSilent(this.audioTrack);
195
+ }
196
+ return mediaStreamTrack.muted || isInadvertentlyStopped || isSilentAudio;
197
+ }
198
+ async removeDocumentEventListeners() {}
199
+ onUnmute(ev) {
200
+ // log.info('Track unmuted', ev);
201
+ }
202
+ removeMediaStreamTrackListeners(mediaStreamTrack) {
203
+ if (!mediaStreamTrack) {
204
+ return undefined;
205
+ }
206
+ const conditionallyRestart = mediaStreamTrack.kind === 'audio' ? this.conditionallyRestartAudio : this.conditionallyRestartVideo;
207
+ mediaStreamTrack.removeEventListener('ended', conditionallyRestart);
208
+ mediaStreamTrack.removeEventListener('mute', conditionallyRestart);
209
+ mediaStreamTrack.removeEventListener('unmute', this.onUnmute);
210
+ return mediaStreamTrack;
211
+ }
212
+ addMediaStreamTrackListeners(mediaStreamTrack) {
213
+ if (!mediaStreamTrack) {
214
+ return null;
215
+ }
216
+ const conditionallyRestart = mediaStreamTrack.kind === 'audio' ? this.conditionallyRestartAudio : this.conditionallyRestartVideo;
217
+ mediaStreamTrack.addEventListener('ended', conditionallyRestart);
218
+ mediaStreamTrack.addEventListener('mute', conditionallyRestart);
219
+ mediaStreamTrack.addEventListener('unmute', this.onUnmute);
220
+ return mediaStreamTrack;
221
+ }
222
+ async setupAudioStream(deviceId, forceStopTrack = false) {
223
+ var _this$currentDevices$2;
224
+ const audioDevices = _classPrivateFieldGet(_localMediaUtils, this).getAudioDevices();
225
+ if (!audioDevices.length) {
226
+ return;
227
+ }
228
+ let audioDeviceId = deviceId;
229
+ if (!audioDeviceId) {
230
+ audioDeviceId = (await this.getOperationalMicDeviceId()).deviceId;
231
+ }
232
+ if (((_this$currentDevices$2 = this.currentDevices.audio) === null || _this$currentDevices$2 === void 0 ? void 0 : _this$currentDevices$2.deviceId) !== audioDeviceId) {
233
+ this.currentDevices.audio = _classPrivateFieldGet(_localMediaUtils, this).getDeviceById(audioDeviceId, 'audioinput');
234
+ }
235
+ if (forceStopTrack) {
236
+ var _this$audioTrack2, _this$rawAudioTrack;
237
+ (_this$audioTrack2 = this.audioTrack) === null || _this$audioTrack2 === void 0 || _this$audioTrack2.stop();
238
+ (_this$rawAudioTrack = this.rawAudioTrack) === null || _this$rawAudioTrack === void 0 || _this$rawAudioTrack.stop();
239
+ }
240
+ try {
241
+ this.rawAudioTrack = await _LocalMediaUtils.default.getAudioTrack();
242
+ } catch (err) {
243
+ console.warn('Failed to acquire audio track: ', err);
244
+ this.rawAudioTrack = undefined;
245
+ }
246
+ this.setAudioTrack(this.rawAudioTrack);
247
+ this.addMediaStreamTrackListeners(this.audioTrack);
248
+ this.emit('AUDIO_TRACK_CHANGE');
249
+ this.setDevice(this.currentDevices.audio);
250
+
251
+ /**
252
+ * NOTE(roerohan): Firefox does not show device labels until permissions are granted.
253
+ * So, we need to repopulate the devices once permission is granted.
254
+ */
255
+ if (this.audioTrack && this.permissions.audio === 'NOT_REQUESTED') {
256
+ await _classPrivateFieldGet(_localMediaUtils, this).repopulateAvailableDevices();
257
+ }
258
+ this.emit('DEVICE_CHANGE', {
259
+ device: this.currentDevices.audio
260
+ });
261
+ }
262
+ onVisibilityChange() {
263
+ // pass
264
+ }
265
+ async setupVideoStream(deviceId, forceStopTrack = false) {
266
+ var _this$currentDevices$3;
267
+ const videoDevices = _classPrivateFieldGet(_localMediaUtils, this).getVideoDevices();
268
+ if (!videoDevices.length) {
269
+ return;
270
+ }
271
+ let videoDeviceId = deviceId;
272
+ if (!videoDeviceId) {
273
+ videoDeviceId = (await this.getOperationalWebcamDeviceId()).deviceId;
274
+ }
275
+ if (((_this$currentDevices$3 = this.currentDevices.video) === null || _this$currentDevices$3 === void 0 ? void 0 : _this$currentDevices$3.deviceId) !== videoDeviceId) {
276
+ this.currentDevices.video = _classPrivateFieldGet(_localMediaUtils, this).getDeviceById(videoDeviceId, 'videoinput');
277
+ }
278
+
279
+ /**
280
+ * NOTE(roerohan): this.videoEnabled is checked, so that upon device change,
281
+ * the video track is not set when the user has turned off his camera.
282
+ */
283
+ if (this.videoEnabled) {
284
+ const videoConstraints = _LocalMediaUtils.default.getVideoConstraints({
285
+ videoDeviceId
286
+ });
287
+ if (!this.rawVideoTrack) {
288
+ try {
289
+ this.rawVideoTrack = await _LocalMediaUtils.default.getVideoTrack(videoConstraints);
290
+ } catch (err) {
291
+ console.warn('Failed to acquire video track: ', err);
292
+ this.rawVideoTrack = undefined;
293
+ }
294
+ }
295
+ this.setVideoTrack(this.rawVideoTrack);
296
+ this.addMediaStreamTrackListeners(this.rawVideoTrack);
297
+ this.emit('VIDEO_TRACK_CHANGE');
298
+ }
299
+ if (forceStopTrack) {
300
+ var _this$videoTrack2, _this$rawVideoTrack;
301
+ (_this$videoTrack2 = this.videoTrack) === null || _this$videoTrack2 === void 0 || _this$videoTrack2.stop();
302
+ (_this$rawVideoTrack = this.rawVideoTrack) === null || _this$rawVideoTrack === void 0 || _this$rawVideoTrack.stop();
303
+ }
304
+ /**
305
+ * NOTE(roerohan): Firefox does not show device labels until permissions are granted.
306
+ * So, we need to repopulate the devices once permission is granted.
307
+ */
308
+ if (this.videoTrack && this.permissions.video === 'NOT_REQUESTED') {
309
+ await _classPrivateFieldGet(_localMediaUtils, this).repopulateAvailableDevices();
310
+ }
311
+ this.emit('DEVICE_CHANGE', {
312
+ device: this.currentDevices.video
313
+ });
314
+ }
315
+ async setupSpeaker(deviceId) {
316
+ var _this$currentDevices$4;
317
+ const speakerDevices = _classPrivateFieldGet(_localMediaUtils, this).getSpeakerDevices();
318
+ if (!speakerDevices.length) {
319
+ return;
320
+ }
321
+ const lastDeviceIndex = speakerDevices.length - 1;
322
+ const speakerDeviceId = deviceId ?? speakerDevices[lastDeviceIndex].deviceId;
323
+ if (((_this$currentDevices$4 = this.currentDevices.speaker) === null || _this$currentDevices$4 === void 0 ? void 0 : _this$currentDevices$4.deviceId) !== speakerDeviceId) {
324
+ // Audio Input devices are same as output devices in mobile
325
+ this.currentDevices.audio = _classPrivateFieldGet(_localMediaUtils, this).getDeviceById(speakerDeviceId, 'audioinput');
326
+ this.currentDevices.speaker = this.currentDevices.audio;
327
+ }
328
+ await this.setDevice(this.currentDevices.audio);
329
+ this.emit('DEVICE_CHANGE', {
330
+ device: this.currentDevices.speaker
331
+ });
332
+ }
333
+ async getOperationalWebcamDeviceId() {
334
+ let videoDevices = _classPrivateFieldGet(_localMediaUtils, this).getVideoDevices();
335
+ if (!videoDevices.length) {
336
+ return {
337
+ isOperational: false,
338
+ deviceId: null
339
+ };
340
+ }
341
+
342
+ /*
343
+ NOTE(ravindra-dyte): Usually external devices come at the bottom,
344
+ By reversing the deviceList and breaking on first operational device
345
+ We are giving preference to external device
346
+ */
347
+
348
+ videoDevices = [...videoDevices].reverse();
349
+ let operationalDeviceId = null;
350
+ for (let deviceIndex = 0; deviceIndex < videoDevices.length; deviceIndex += 1) {
351
+ try {
352
+ operationalDeviceId = videoDevices[deviceIndex].deviceId;
353
+ break;
354
+ } catch (err) {}
355
+ }
356
+ return operationalDeviceId ? {
357
+ isOperational: true,
358
+ deviceId: operationalDeviceId
359
+ } : {
360
+ isOperational: false,
361
+ deviceId: videoDevices[0].deviceId
362
+ };
363
+ }
364
+ async getOperationalMicDeviceId() {
365
+ let audioDevices = _classPrivateFieldGet(_localMediaUtils, this).getAudioDevices();
366
+ if (!audioDevices.length) {
367
+ return {
368
+ isOperational: false,
369
+ deviceId: null
370
+ };
371
+ }
372
+ /*
373
+ NOTE(ravindra-dyte): Usually external devices come at the bottom,
374
+ By reversing the deviceList and breaking on first operational device
375
+ We are giving preference to external device
376
+ */
377
+
378
+ audioDevices = [...audioDevices].reverse();
379
+ let operationalDeviceId = null;
380
+ for (let deviceIndex = 0; deviceIndex < audioDevices.length; deviceIndex += 1) {
381
+ try {
382
+ const audioTrack = await _LocalMediaUtils.default.getAudioTrack();
383
+ const isSilent = await checkIfAudioTrackIsSilent(audioTrack);
384
+ audioTrack.stop();
385
+ audioTrack.release();
386
+ if (!isSilent) {
387
+ operationalDeviceId = audioDevices[deviceIndex].deviceId;
388
+ break;
389
+ }
390
+ } catch (err) {
391
+ console.warn('Failed to acquire audio track: ', err);
392
+ }
393
+ }
394
+ return operationalDeviceId ? {
395
+ isOperational: true,
396
+ deviceId: operationalDeviceId
397
+ } : {
398
+ isOperational: false,
399
+ deviceId: audioDevices[0].deviceId
400
+ };
401
+ }
402
+ async setupStreams({
403
+ audio,
404
+ video
405
+ }) {
406
+ try {
407
+ const permResult = await (0, _PermissionHandler.setupPermissions)(audio, video);
408
+ this.permissions.video = permResult.camera;
409
+ this.permissions.audio = permResult.microphone;
410
+ } catch (val) {
411
+ this.permissions.video = val.camera ?? false;
412
+ this.permissions.audio = val.microphone ?? false;
413
+ }
414
+ this.emit('MEDIA_PERMISSION_UPDATE', {
415
+ kind: 'audio',
416
+ message: this.permissions.audio
417
+ });
418
+ this.emit('MEDIA_PERMISSION_UPDATE', {
419
+ kind: 'video',
420
+ message: this.permissions.video
421
+ });
422
+ const constraints = {};
423
+ if (!this.currentDevices) {
424
+ this.currentDevices = {
425
+ audio: undefined,
426
+ video: undefined,
427
+ speaker: undefined
428
+ };
429
+ }
430
+ if (audio) {
431
+ const audioDevices = _classPrivateFieldGet(_localMediaUtils, this).getAudioDevices();
432
+ if (audioDevices.length !== 0) {
433
+ const audioDeviceId = (await this.getOperationalMicDeviceId()).deviceId;
434
+ this.currentDevices.audio = _classPrivateFieldGet(_localMediaUtils, this).getDeviceById(audioDeviceId, 'audioinput');
435
+ constraints.audio = true;
436
+ }
437
+ }
438
+ if (video) {
439
+ const videoDevices = _classPrivateFieldGet(_localMediaUtils, this).getVideoDevices();
440
+ if (videoDevices.length !== 0) {
441
+ const videoDeviceId = (await this.getOperationalWebcamDeviceId()).deviceId;
442
+ this.currentDevices.video = _classPrivateFieldGet(_localMediaUtils, this).getDeviceById(videoDeviceId, 'videoinput');
443
+ const videoConstraints = _LocalMediaUtils.default.getVideoConstraints({
444
+ videoDeviceId
445
+ });
446
+ constraints.video = videoConstraints.video;
447
+ }
448
+ }
449
+ if (audio) await this.setupAudioStream();
450
+ if (video) await this.setupVideoStream();
451
+ if (this.audioTrack) this.audioEnabled = true;else this.audioEnabled = false;
452
+ if (this.videoTrack) this.videoEnabled = true;else this.videoEnabled = false;
453
+ this.screenShareEnabled = false;
454
+
455
+ // Setting default audio output to speaker
456
+ await this.setupSpeaker();
457
+
458
+ // Setup Foreground Service after handling permissions
459
+ if (_reactNative.Platform.OS === 'android') {
460
+ _classPrivateFieldSet(_appStateSubscription, this, _reactNative.AppState.addEventListener('change', this._handleAppStateChange));
461
+ }
462
+ }
463
+ stopScreenShareTracks(tracks = {}) {
464
+ const {
465
+ audio = true,
466
+ video = true
467
+ } = tracks;
468
+ if (audio) {
469
+ var _this$screenShareTrac;
470
+ (_this$screenShareTrac = this.screenShareTracks) === null || _this$screenShareTrac === void 0 || (_this$screenShareTrac = _this$screenShareTrac.audio) === null || _this$screenShareTrac === void 0 || _this$screenShareTrac.stop();
471
+ }
472
+ if (video) {
473
+ var _this$screenShareTrac2;
474
+ (_this$screenShareTrac2 = this.screenShareTracks) === null || _this$screenShareTrac2 === void 0 || (_this$screenShareTrac2 = _this$screenShareTrac2.video) === null || _this$screenShareTrac2 === void 0 || _this$screenShareTrac2.stop();
475
+ }
476
+ if (audio && video) {
477
+ this.screenShareEnabled = false;
478
+ }
479
+ }
480
+ removeScreenShareTracks(tracks) {
481
+ var _this$screenShareTrac3;
482
+ (_this$screenShareTrac3 = this.screenShareTracks.video) === null || _this$screenShareTrac3 === void 0 || _this$screenShareTrac3.removeEventListener('ended', this.onScreenShareEnded);
483
+ this.stopScreenShareTracks(tracks);
484
+ this.screenShareTracks = {
485
+ audio: undefined,
486
+ video: undefined
487
+ };
488
+ }
489
+ setAudioTrack(audioTrack) {
490
+ if (audioTrack === this.audioTrack) {
491
+ return;
492
+ }
493
+ if (audioTrack === undefined) {
494
+ this.stopAudioTrack();
495
+ }
496
+ this.audioTrack = audioTrack;
497
+ }
498
+ setVideoTrack(videoTrack) {
499
+ if (videoTrack === this.videoTrack) {
500
+ return;
501
+ }
502
+ if (videoTrack === undefined) {
503
+ this.stopVideoTrack();
504
+ }
505
+ this.videoTrack = videoTrack;
506
+ }
507
+ setScreenShareTracks(tracks) {
508
+ var _this$screenShareTrac4;
509
+ const {
510
+ audio,
511
+ video
512
+ } = tracks;
513
+ // console.log('SetScreenshare called');
514
+ if (!audio || !video) {
515
+ this.stopScreenShareTracks({
516
+ audio: !!audio,
517
+ video: !!video
518
+ });
519
+ }
520
+ this.screenShareTracks = tracks;
521
+ (_this$screenShareTrac4 = this.screenShareTracks.video) === null || _this$screenShareTrac4 === void 0 || _this$screenShareTrac4.addEventListener('ended', this.onScreenShareEnded.bind(this));
522
+ }
523
+ onScreenShareEnded() {
524
+ this.emit('SCREENSHARE_ENDED');
525
+ }
526
+ async disableAudio() {
527
+ await this.toggleAudio();
528
+ }
529
+ async enableAudio() {
530
+ await this.toggleAudio();
531
+ }
532
+ async toggleAudio() {
533
+ if (this.permissions.audio !== 'ACCEPTED') {
534
+ try {
535
+ const permResult = await (0, _PermissionHandler.setupPermissions)(true, false);
536
+ this.permissions.audio = permResult.microphone;
537
+ } catch (val) {
538
+ this.permissions.audio = val.microphone ?? false;
539
+ }
540
+ }
541
+ this.emit('MEDIA_PERMISSION_UPDATE', {
542
+ kind: 'audio',
543
+ message: this.permissions.audio
544
+ });
545
+ if (this.permissions.audio === 'DENIED' || this.permissions.audio === 'NOT_REQUESTED') {
546
+ this.audioEnabled = false;
547
+ return;
548
+ }
549
+ if (this.audioEnabled) {
550
+ this.audioEnabled = false;
551
+ if (this.audioTrack) {
552
+ this.audioTrack.enabled = this.audioEnabled;
553
+ }
554
+ return;
555
+ }
556
+ try {
557
+ /**
558
+ * NOTE (@madhugb): We need to setup new stream,
559
+ * if the audio track is not preset or it has ended
560
+ */
561
+ if (!this.audioTrack || this.audioTrack.readyState === 'ended') {
562
+ var _this$currentDevices$5;
563
+ await this.setupAudioStream((_this$currentDevices$5 = this.currentDevices.audio) === null || _this$currentDevices$5 === void 0 ? void 0 : _this$currentDevices$5.deviceId);
564
+ }
565
+ // if we still can't get a track after setting up audio stream
566
+ // do not toggle the audio state
567
+ if (!this.audioTrack) {
568
+ this.audioEnabled = false;
569
+ return;
570
+ }
571
+ this.audioEnabled = true;
572
+ } catch (ex) {
573
+ this.audioEnabled = false;
574
+ this.audioTrack = undefined;
575
+ this.rawAudioTrack = undefined;
576
+ }
577
+ if (this.audioTrack) {
578
+ this.audioTrack.enabled = true;
579
+ }
580
+ }
581
+ async enableVideo() {
582
+ await this.toggleVideo();
583
+ }
584
+ async disableVideo() {
585
+ await this.toggleVideo();
586
+ }
587
+ async toggleVideo() {
588
+ var _this$currentDevices$6;
589
+ if (this.permissions.video !== 'ACCEPTED') {
590
+ try {
591
+ const permResult = await (0, _PermissionHandler.setupPermissions)(false, true);
592
+ this.permissions.video = permResult.camera;
593
+ } catch (val) {
594
+ this.permissions.video = val.camera ?? false;
595
+ }
596
+ }
597
+ this.emit('MEDIA_PERMISSION_UPDATE', {
598
+ kind: 'video',
599
+ message: this.permissions.video
600
+ });
601
+ if (this.permissions.video === 'DENIED' || this.permissions.video === 'NOT_REQUESTED') {
602
+ this.videoEnabled = false;
603
+ return;
604
+ }
605
+ if (this.videoEnabled) {
606
+ this.stopVideoTrack();
607
+ this.videoEnabled = false;
608
+ return;
609
+ }
610
+ /**
611
+ * NOTE(roerohan): The videoEnabled flag is used inside the setupVideoStream method
612
+ * hence it must be set to true first.
613
+ */
614
+ this.videoEnabled = true;
615
+ await this.setupVideoStream((_this$currentDevices$6 = this.currentDevices.video) === null || _this$currentDevices$6 === void 0 ? void 0 : _this$currentDevices$6.deviceId);
616
+ }
617
+ async setAudioDevice(device) {
618
+ await this.setupAudioStream(device.deviceId);
619
+ }
620
+ async setVideoDevice(device) {
621
+ if (this.videoEnabled) {
622
+ this.stopVideoTrack();
623
+ }
624
+ await this.setupVideoStream(device.deviceId);
625
+ }
626
+ async setSpeakerDevice(device) {
627
+ await this.setupSpeaker(device.deviceId);
628
+ }
629
+ async setDevice(route) {
630
+ await _classPrivateFieldGet(_localMediaUtils, this).chooseAudioRoute(route.deviceId);
631
+ }
632
+ async oniOSBroadcastStart() {
633
+ this.setScreenShareTracks(await _LocalMediaUtils.default.getScreenShareTracks());
634
+ this.screenShareEnabled = true;
635
+ this.emit('SCREENSHARE_TRACK_CHANGE');
636
+ }
637
+ async oniOSBroadcastStop() {
638
+ if (this.screenShareEnabled) {
639
+ this.removeScreenShareTracks();
640
+ this.emit('SCREENSHARE_TRACK_CHANGE');
641
+ return;
642
+ }
643
+ }
644
+ async toggleScreenShare() {
645
+ if (this.screenShareEnabled && _reactNative.Platform.OS !== 'ios') {
646
+ this.removeScreenShareTracks();
647
+ try {
648
+ await RTKHelper.stopService();
649
+ } catch (e) {
650
+ console.warn('Failed to stop foreground service', e);
651
+ }
652
+ return;
653
+ }
654
+ if (_reactNative.Platform.OS === 'ios' && this.screenShareEnabled) {
655
+ _reactNative.NativeModules.RTKScreensharePickerView.showScreenSharePickerView();
656
+ return;
657
+ }
658
+ if (_reactNative.Platform.OS === 'android') {
659
+ this._pendingScreenShare = true;
660
+ await this.configureForeground();
661
+ try {
662
+ this.setScreenShareTracks(await _LocalMediaUtils.default.getScreenShareTracks());
663
+ this.screenShareEnabled = true;
664
+ } catch (e) {
665
+ console.warn('Failed to start screenshare', e);
666
+ this.screenShareEnabled = false;
667
+ await RTKHelper.stopService();
668
+ this._pendingScreenShare = false;
669
+ } finally {
670
+ this._pendingScreenShare = false;
671
+ }
672
+ }
673
+ if (_reactNative.Platform.OS === 'ios') {
674
+ _reactNative.NativeModules.RTKScreensharePickerView.showScreenSharePickerView();
675
+ }
676
+ }
677
+ async enableScreenShare() {
678
+ await this.toggleScreenShare();
679
+ }
680
+ async disableScreenShare() {
681
+ await this.toggleScreenShare();
682
+ }
683
+ getAllDevices() {
684
+ return _classPrivateFieldGet(_localMediaUtils, this).availableDevices;
685
+ }
686
+ getCurrentDevices() {
687
+ return this.currentDevices;
688
+ }
689
+ getDeviceById(deviceId, kind) {
690
+ return _classPrivateFieldGet(_localMediaUtils, this).getDeviceById(deviceId, kind);
691
+ }
692
+ getAudioDevices() {
693
+ return _classPrivateFieldGet(_localMediaUtils, this).getAudioDevices();
694
+ }
695
+ getVideoDevices() {
696
+ return _classPrivateFieldGet(_localMediaUtils, this).getVideoDevices();
697
+ }
698
+ getSpeakerDevices() {
699
+ return _classPrivateFieldGet(_localMediaUtils, this).getSpeakerDevices();
700
+ }
701
+ async onDeviceChange(changedDevices, forceDeviceChange) {
702
+ let addedDevice;
703
+ let removedDevice;
704
+ if (changedDevices.added.length) [addedDevice] = changedDevices.added;
705
+ if (changedDevices.removed.length) [removedDevice] = changedDevices.removed;
706
+
707
+ /**
708
+ * NOTE(roerohan): forceStopTrack is set required to be set to true for firefox.
709
+ * https://stackoverflow.com/questions/59068146/navigator-mediadevices-getusermedia-api-rejecting-with-error-notreadableerror
710
+ * forceStopTrack is the second argument of setupAudioStream and setupVideoStream.
711
+ */
712
+ if (addedDevice) {
713
+ if (addedDevice.kind === 'audioinput') {
714
+ if (this.permissions.audio === 'DENIED' || this.permissions.audio === 'NOT_REQUESTED') {
715
+ await this.setupSpeaker(addedDevice.deviceId);
716
+ } else {
717
+ await this.setupAudioStream(addedDevice.deviceId);
718
+ }
719
+ } else if (addedDevice.kind === 'videoinput') {
720
+ await this.setupVideoStream(addedDevice.deviceId);
721
+ } else if (addedDevice.kind === 'audiooutput') {
722
+ await this.setupSpeaker(addedDevice.deviceId);
723
+ }
724
+ this.emit('AUDIO_TRACK_CHANGE');
725
+ }
726
+ if (removedDevice) {
727
+ if (removedDevice.kind === 'audioinput') {
728
+ if (this.permissions.audio === 'DENIED' || this.permissions.audio === 'NOT_REQUESTED') {
729
+ await this.setupSpeaker();
730
+ } else {
731
+ await this.setupAudioStream();
732
+ }
733
+ } else if (removedDevice.kind === 'videoinput') {
734
+ await this.setupVideoStream();
735
+ } else if (removedDevice.kind === 'audiooutput') {
736
+ await this.setupSpeaker();
737
+ }
738
+ this.emit('AUDIO_TRACK_CHANGE');
739
+ }
740
+ if (changedDevices.added.length || changedDevices.removed.length) {
741
+ this.emit('DEVICE_LIST_UPDATED', changedDevices);
742
+ }
743
+ }
744
+ static async init(_) {
745
+ const localMediaUtils = await _LocalMediaUtils.default.init();
746
+ return new LocalMediaHandler(localMediaUtils);
747
+ }
748
+ emit(event, ...args) {
749
+ return super.emit(event, ...args);
750
+ }
751
+ on(event, listener) {
752
+ return super.on(event, listener);
753
+ }
754
+ destruct() {
755
+ // TODO: Do not remove native broadcast listeners when going OFF_STAGE in webinar
756
+ // this.#localMediaUtils.destruct();
757
+ if (_reactNative.Platform.OS === 'android') _classPrivateFieldGet(_appStateSubscription, this).remove();
758
+ _BackgroundHandler.default.stop();
759
+ try {
760
+ if (_reactNative.Platform.OS === 'android') RTKHelper.stopService();
761
+ } catch (_err) {}
762
+ // InCallManger.stop(undefined);
763
+ }
764
+ stopAudioTrack() {
765
+ var _this$rawAudioTrack2, _this$audioTrack3, _this$rawAudioTrack3, _this$audioTrack4;
766
+ (_this$rawAudioTrack2 = this.rawAudioTrack) === null || _this$rawAudioTrack2 === void 0 || _this$rawAudioTrack2.stop();
767
+ (_this$audioTrack3 = this.audioTrack) === null || _this$audioTrack3 === void 0 || _this$audioTrack3.stop();
768
+ (_this$rawAudioTrack3 = this.rawAudioTrack) === null || _this$rawAudioTrack3 === void 0 || _this$rawAudioTrack3.release();
769
+ (_this$audioTrack4 = this.audioTrack) === null || _this$audioTrack4 === void 0 || _this$audioTrack4.release();
770
+ this.audioEnabled = false;
771
+ this.audioTrack = undefined;
772
+ this.rawAudioTrack = undefined;
773
+ }
774
+ stopVideoTrack() {
775
+ var _this$rawVideoTrack2, _this$videoTrack3, _this$rawVideoTrack3, _this$videoTrack4;
776
+ (_this$rawVideoTrack2 = this.rawVideoTrack) === null || _this$rawVideoTrack2 === void 0 || _this$rawVideoTrack2.stop();
777
+ (_this$videoTrack3 = this.videoTrack) === null || _this$videoTrack3 === void 0 || _this$videoTrack3.stop();
778
+ (_this$rawVideoTrack3 = this.rawVideoTrack) === null || _this$rawVideoTrack3 === void 0 || _this$rawVideoTrack3.release();
779
+ (_this$videoTrack4 = this.videoTrack) === null || _this$videoTrack4 === void 0 || _this$videoTrack4.release();
780
+ this.videoTrack = undefined;
781
+ this.rawVideoTrack = undefined;
782
+ }
783
+ }
784
+ exports.default = LocalMediaHandler;
785
+ //# sourceMappingURL=LocalMediaHandler.js.map