@cloudflare/realtimekit-react-native 0.1.2-staging.1 → 0.1.2-staging.11
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/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/com/reactnativecore/DyteHelperModule.java +1 -0
- package/android/src/main/java/com/reactnativecore/ForegroundService.java +1 -1
- package/android/src/main/java/com/reactnativecore/NotificationHelper.java +11 -12
- package/ios/RNInCallManager.m +46 -28
- package/ios/screenshare/DyteScreenshareHandler.swift +2 -4
- package/lib/BackgroundHandler.js +15 -5
- package/lib/LocalMediaHandler.d.ts +9 -11
- package/lib/LocalMediaHandler.js +99 -82
- package/lib/LocalMediaUtils.js +0 -2
- package/package.json +3 -3
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/>
|
|
7
7
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
|
8
8
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
|
|
9
|
+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
|
9
10
|
<uses-permission android:name="android.permission.CAMERA"/>
|
|
10
11
|
<uses-permission android:name="android.permission.INTERNET"/>
|
|
11
12
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
|
@@ -134,6 +134,7 @@ public class DyteHelperModule extends ReactContextBaseJavaModule {
|
|
|
134
134
|
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
|
135
135
|
if ((ForegroundService.class).getName().equals(service.service.getClassName())) {
|
|
136
136
|
promise.resolve(true);
|
|
137
|
+
return;
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
promise.resolve(false);
|
|
@@ -28,7 +28,7 @@ public class ForegroundService extends Service {
|
|
|
28
28
|
if (notification != null) {
|
|
29
29
|
try {
|
|
30
30
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
31
|
-
startForeground(notificationHelper.NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
|
|
31
|
+
startForeground(notificationHelper.NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
|
|
32
32
|
} else {
|
|
33
33
|
startForeground(notificationHelper.NOTIFICATION_ID, notification);
|
|
34
34
|
}
|
|
@@ -22,9 +22,9 @@ import java.util.Random;
|
|
|
22
22
|
|
|
23
23
|
class NotificationHelper {
|
|
24
24
|
public static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
|
|
25
|
-
private static final String CHANNEL_ID = "
|
|
26
|
-
private static final String CHANNEL_NAME = "
|
|
27
|
-
private static final String CHANNEL_DESC = "
|
|
25
|
+
private static final String CHANNEL_ID = "RealtimeKitNotificationChannel";
|
|
26
|
+
private static final String CHANNEL_NAME = "Screen Sharing";
|
|
27
|
+
private static final String CHANNEL_DESC = "Screen Sharing";
|
|
28
28
|
|
|
29
29
|
private static NotificationHelper instance = null;
|
|
30
30
|
private NotificationManager mNotificationManager;
|
|
@@ -83,18 +83,17 @@ class NotificationHelper {
|
|
|
83
83
|
|
|
84
84
|
builder
|
|
85
85
|
.setCategory(NotificationCompat.CATEGORY_CALL)
|
|
86
|
-
.setContentTitle("
|
|
87
|
-
.setContentText("
|
|
88
|
-
.setPriority(NotificationCompat.
|
|
86
|
+
.setContentTitle("Screen Share")
|
|
87
|
+
.setContentText("You are sharing your screen")
|
|
88
|
+
.setPriority(NotificationCompat.PRIORITY_LOW)
|
|
89
89
|
.setContentIntent(pendingIntent)
|
|
90
|
-
.setOngoing(
|
|
91
|
-
.
|
|
92
|
-
.
|
|
93
|
-
.setAutoCancel(false)
|
|
90
|
+
.setOngoing(false)
|
|
91
|
+
.setUsesChronometer(false)
|
|
92
|
+
.setAutoCancel(true)
|
|
94
93
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
95
94
|
.setOnlyAlertOnce(true)
|
|
96
|
-
.setSmallIcon(appIconResId)
|
|
97
|
-
|
|
95
|
+
.setSmallIcon(appIconResId)
|
|
96
|
+
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE);
|
|
98
97
|
if(largeIcon != null){
|
|
99
98
|
builder.setLargeIcon(largeIcon);
|
|
100
99
|
}
|
package/ios/RNInCallManager.m
CHANGED
|
@@ -181,8 +181,7 @@ RCT_EXPORT_METHOD(chooseAudioRoute: (NSString *)audioRoute Promise:(RCTPromiseR
|
|
|
181
181
|
if (![_userSelectedAudioRoute isEqualToString:_currentAudioRoute]) {
|
|
182
182
|
if ([audioRoute isEqual: @"SPEAKER_PHONE"] || [audioRoute isEqualToString:@"speaker"]) {
|
|
183
183
|
_forceSpeakerOn = 1;
|
|
184
|
-
[self
|
|
185
|
-
success = true;
|
|
184
|
+
success = [self routeAudioFromSpeakerphone];
|
|
186
185
|
} else if ([audioRoute isEqualToString:@"WIRED_HEADSET"] || [audioRoute isEqualToString:@"wired"]) {
|
|
187
186
|
_forceSpeakerOn = 0;
|
|
188
187
|
success = [self routeAudioFromEarpiece];
|
|
@@ -286,8 +285,19 @@ RCT_EXPORT_METHOD(setSpeakerphoneOn:(BOOL)enable)
|
|
|
286
285
|
}
|
|
287
286
|
|
|
288
287
|
- (BOOL)routeAudioFromBluetooth {
|
|
288
|
+
BOOL success;
|
|
289
289
|
NSError *error = nil;
|
|
290
290
|
_audioSession = [AVAudioSession sharedInstance];
|
|
291
|
+
success = [_audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
|
|
292
|
+
withOptions:AVAudioSessionCategoryOptionAllowBluetooth
|
|
293
|
+
error:&error];
|
|
294
|
+
if (!success) {
|
|
295
|
+
NSLog(@"📕 Cannot set category due to error: %@", error);
|
|
296
|
+
}
|
|
297
|
+
success = [_audioSession setMode:AVAudioSessionModeVoiceChat error: &error];
|
|
298
|
+
if (!success) {
|
|
299
|
+
NSLog(@"📕 Cannot set mode due to error: %@", error);
|
|
300
|
+
}
|
|
291
301
|
for (AVAudioSessionPortDescription* input in [_audioSession availableInputs]) {
|
|
292
302
|
if ([[input portType] isEqualToString:AVAudioSessionPortBluetoothHFP] ||
|
|
293
303
|
[[input portType] isEqualToString:AVAudioSessionPortBluetoothA2DP] ||
|
|
@@ -351,7 +361,7 @@ RCT_EXPORT_METHOD(setSpeakerphoneOn:(BOOL)enable)
|
|
|
351
361
|
@try {
|
|
352
362
|
success = [_audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
|
|
353
363
|
withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker
|
|
354
|
-
error
|
|
364
|
+
error:&error];
|
|
355
365
|
if (!success) {
|
|
356
366
|
NSLog(@"📕 Cannot set category due to error: %@", error);
|
|
357
367
|
}
|
|
@@ -549,6 +559,11 @@ RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
|
|
|
549
559
|
{
|
|
550
560
|
// NSLog(@"👉 Checking if Bluetooth device is connected");
|
|
551
561
|
NSMutableArray *devices = [NSMutableArray array];
|
|
562
|
+
NSError *error = nil;
|
|
563
|
+
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord
|
|
564
|
+
withOptions:AVAudioSessionCategoryOptionAllowBluetooth
|
|
565
|
+
error:&error];
|
|
566
|
+
[[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:nil];
|
|
552
567
|
AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];
|
|
553
568
|
for (AVAudioSessionPortDescription* desc in [route outputs]) {
|
|
554
569
|
// NSLog(@"🧑💻 Bluetooth Desc: %@", desc);
|
|
@@ -558,6 +573,20 @@ RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
|
|
|
558
573
|
[devices addObject:[desc portName]];
|
|
559
574
|
}
|
|
560
575
|
}
|
|
576
|
+
|
|
577
|
+
// If no Bluetooth device found in current route, check available outputs
|
|
578
|
+
if (devices.count == 0) {
|
|
579
|
+
NSArray<AVAudioSessionPortDescription *> *inputs = [route inputs];
|
|
580
|
+
|
|
581
|
+
// Check if Bluetooth is available in inputs (for headsets that function as both input and output)
|
|
582
|
+
for (AVAudioSessionPortDescription* desc in inputs) {
|
|
583
|
+
if ([[desc portType] isEqualToString:AVAudioSessionPortBluetoothHFP] ||
|
|
584
|
+
[[desc portType] isEqualToString:AVAudioSessionPortBluetoothLE]) {
|
|
585
|
+
[devices addObject:[desc portName]];
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
561
590
|
// NSLog(@"🧑💻 Bluetooth Devices %@", devices);
|
|
562
591
|
if (!devices || !devices.count){
|
|
563
592
|
resolve(@NO);
|
|
@@ -620,11 +649,6 @@ RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
|
|
|
620
649
|
[self audioSessionSetMode:audioMode
|
|
621
650
|
callerMemo:NSStringFromSelector(_cmd)];
|
|
622
651
|
|
|
623
|
-
@try {
|
|
624
|
-
[self sendEventWithName:@"onAudioDeviceChanged" body:@{@"devices": audioMode}];
|
|
625
|
-
} @catch (NSException *exception) {
|
|
626
|
-
NSLog(@"Error sending event 'onAudioDeviceChanged': %@", exception.reason);
|
|
627
|
-
}
|
|
628
652
|
// NSLog(@"👨💻 RNInCallManager.updateAudioRoute() audio mode has changed to %@", audioMode);
|
|
629
653
|
return true;
|
|
630
654
|
} else {
|
|
@@ -943,60 +967,63 @@ RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
|
|
|
943
967
|
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: NewDeviceAvailable");
|
|
944
968
|
if ([self checkAudioRoute:@[AVAudioSessionPortHeadsetMic]
|
|
945
969
|
routeType:@"input"]) {
|
|
946
|
-
|
|
970
|
+
self->_forceSpeakerOn = 0;
|
|
947
971
|
@try {
|
|
948
972
|
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
949
973
|
body:@{
|
|
950
974
|
@"availableAudioDeviceList": @"[speaker, earpiece, wired]",
|
|
951
|
-
@"selectedAudioDevice":
|
|
975
|
+
@"selectedAudioDevice": @"wired",
|
|
952
976
|
}];
|
|
953
977
|
} @catch (NSException *exception) {
|
|
954
978
|
NSLog(@"Error sending event 'onAudioDeviceChanged' (HeadsetMic): %@", exception.reason);
|
|
955
979
|
}
|
|
956
980
|
} else if ([self checkAudioRoute:@[AVAudioSessionPortHeadphones]
|
|
957
981
|
routeType:@"output"]) {
|
|
958
|
-
|
|
982
|
+
self->_forceSpeakerOn = 0;
|
|
959
983
|
@try {
|
|
960
984
|
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
961
985
|
body:@{
|
|
962
986
|
@"availableAudioDeviceList": @"[speaker, earpiece, wired]",
|
|
963
|
-
@"selectedAudioDevice":
|
|
987
|
+
@"selectedAudioDevice": @"wired",
|
|
964
988
|
}];
|
|
965
989
|
} @catch (NSException *exception) {
|
|
966
990
|
NSLog(@"Error sending event 'onAudioDeviceChanged' (Headphones): %@", exception.reason);
|
|
967
991
|
}
|
|
968
992
|
} else if ([self checkAudioRoute:@[AVAudioSessionPortBluetoothHFP]
|
|
969
993
|
routeType:@"input"]) {
|
|
970
|
-
_forceSpeakerOn = 0;
|
|
994
|
+
self->_forceSpeakerOn = 0;
|
|
995
|
+
[self routeAudioFromBluetooth];
|
|
971
996
|
@try {
|
|
972
997
|
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
973
998
|
body:@{
|
|
974
999
|
@"availableAudioDeviceList": @"[speaker, earpiece, bluetooth]",
|
|
975
|
-
@"selectedAudioDevice":
|
|
1000
|
+
@"selectedAudioDevice": @"bluetooth",
|
|
976
1001
|
}];
|
|
977
1002
|
} @catch (NSException *exception) {
|
|
978
1003
|
NSLog(@"Error sending event 'onAudioDeviceChanged' (BluetoothHFP): %@", exception.reason);
|
|
979
1004
|
}
|
|
980
1005
|
} else if ([self checkAudioRoute:@[AVAudioSessionPortBluetoothA2DP]
|
|
981
1006
|
routeType:@"input"]) {
|
|
982
|
-
_forceSpeakerOn = 0;
|
|
1007
|
+
self->_forceSpeakerOn = 0;
|
|
1008
|
+
[self routeAudioFromBluetooth];
|
|
983
1009
|
@try {
|
|
984
1010
|
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
985
1011
|
body:@{
|
|
986
1012
|
@"availableAudioDeviceList": @"[speaker, earpiece, bluetooth]",
|
|
987
|
-
@"selectedAudioDevice":
|
|
1013
|
+
@"selectedAudioDevice": @"bluetooth",
|
|
988
1014
|
}];
|
|
989
1015
|
} @catch (NSException *exception) {
|
|
990
1016
|
NSLog(@"Error sending event 'onAudioDeviceChanged' (BluetoothA2DP): %@", exception.reason);
|
|
991
1017
|
}
|
|
992
1018
|
} else if ([self checkAudioRoute:@[AVAudioSessionPortBluetoothLE]
|
|
993
1019
|
routeType:@"input"]) {
|
|
994
|
-
_forceSpeakerOn = 0;
|
|
1020
|
+
self->_forceSpeakerOn = 0;
|
|
1021
|
+
[self routeAudioFromBluetooth];
|
|
995
1022
|
@try {
|
|
996
1023
|
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
997
1024
|
body:@{
|
|
998
1025
|
@"availableAudioDeviceList": @"[speaker, earpiece, bluetooth]",
|
|
999
|
-
@"selectedAudioDevice":
|
|
1026
|
+
@"selectedAudioDevice": @"bluetooth",
|
|
1000
1027
|
}];
|
|
1001
1028
|
} @catch (NSException *exception) {
|
|
1002
1029
|
NSLog(@"Error sending event 'onAudioDeviceChanged' (BluetoothLE): %@", exception.reason);
|
|
@@ -1018,16 +1045,7 @@ RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
|
|
|
1018
1045
|
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: CategoryChange. category=%@ mode=%@", self->_audioSession.category, self->_audioSession.mode);
|
|
1019
1046
|
break;
|
|
1020
1047
|
case AVAudioSessionRouteChangeReasonOverride:
|
|
1021
|
-
@
|
|
1022
|
-
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: Override");
|
|
1023
|
-
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
1024
|
-
body:@{
|
|
1025
|
-
@"availableAudioDeviceList": @"[speaker, earpiece]",
|
|
1026
|
-
@"selectedAudioDevice": @"speaker",
|
|
1027
|
-
}];
|
|
1028
|
-
} @catch (NSException *exception) {
|
|
1029
|
-
NSLog(@"Error sending event 'onAudioDeviceChanged' (Override): %@", exception.reason);
|
|
1030
|
-
}
|
|
1048
|
+
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: Override");
|
|
1031
1049
|
break;
|
|
1032
1050
|
case AVAudioSessionRouteChangeReasonWakeFromSleep:
|
|
1033
1051
|
// NSLog(@"RNInCallManager.AudioRouteChange.Reason: WakeFromSleep");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ReplayKit
|
|
2
2
|
|
|
3
|
-
open class
|
|
3
|
+
open class RTKScreenshareHandler: RPBroadcastSampleHandler {
|
|
4
4
|
|
|
5
5
|
private var clientConnection: DyteSocketConnection?
|
|
6
6
|
private var uploader: DyteScreenshareUploader?
|
|
@@ -21,7 +21,6 @@ open class DyteScreenshareHandler: RPBroadcastSampleHandler {
|
|
|
21
21
|
super.init()
|
|
22
22
|
if let connection = DyteSocketConnection(filePath: socketFilePath) {
|
|
23
23
|
clientConnection = connection
|
|
24
|
-
print("Setup Connection")
|
|
25
24
|
setupConnection()
|
|
26
25
|
uploader = DyteScreenshareUploader(connection: connection, bundleIdentifier: bundleIdentifier)
|
|
27
26
|
}
|
|
@@ -49,7 +48,6 @@ open class DyteScreenshareHandler: RPBroadcastSampleHandler {
|
|
|
49
48
|
|
|
50
49
|
public override func broadcastFinished() {
|
|
51
50
|
// User has requested to finish the broadcast.
|
|
52
|
-
print("Broadcast Stopped")
|
|
53
51
|
DyteDarwinNotificationCenter.shared.postNotification(.broadcastStopped)
|
|
54
52
|
clientConnection?.close()
|
|
55
53
|
}
|
|
@@ -68,7 +66,7 @@ open class DyteScreenshareHandler: RPBroadcastSampleHandler {
|
|
|
68
66
|
}
|
|
69
67
|
}
|
|
70
68
|
|
|
71
|
-
private extension
|
|
69
|
+
private extension RTKScreenshareHandler {
|
|
72
70
|
|
|
73
71
|
func setupConnection() {
|
|
74
72
|
clientConnection?.didClose = { [weak self] error in
|
package/lib/BackgroundHandler.js
CHANGED
|
@@ -13,7 +13,9 @@ class BackgroundTimer {
|
|
|
13
13
|
delete this.callbacks[id];
|
|
14
14
|
}
|
|
15
15
|
else {
|
|
16
|
-
|
|
16
|
+
Platform.OS === 'android'
|
|
17
|
+
? DyteRNBackgroundTimer.backgroundTimerSetTimeout(id, this.callbacks[id].timeout)
|
|
18
|
+
: DyteRNBackgroundTimer.setTimeout(id, this.callbacks[id].timeout);
|
|
17
19
|
}
|
|
18
20
|
callback();
|
|
19
21
|
}
|
|
@@ -21,11 +23,15 @@ class BackgroundTimer {
|
|
|
21
23
|
}
|
|
22
24
|
// Original API
|
|
23
25
|
start(delay = 0) {
|
|
24
|
-
return
|
|
26
|
+
return Platform.OS === 'android'
|
|
27
|
+
? DyteRNBackgroundTimer.backgroundTimerStart(delay)
|
|
28
|
+
: DyteRNBackgroundTimer.start(delay);
|
|
25
29
|
}
|
|
26
30
|
stop() {
|
|
27
31
|
Emitter.removeAllListeners('backgroundTimer.timeout');
|
|
28
|
-
return
|
|
32
|
+
return Platform.OS === 'android'
|
|
33
|
+
? DyteRNBackgroundTimer.backgroundTimerStop()
|
|
34
|
+
: DyteRNBackgroundTimer.stop();
|
|
29
35
|
}
|
|
30
36
|
runBackgroundTimer(callback, delay) {
|
|
31
37
|
const EventEmitter = Platform.select({
|
|
@@ -57,7 +63,9 @@ class BackgroundTimer {
|
|
|
57
63
|
interval: false,
|
|
58
64
|
timeout,
|
|
59
65
|
};
|
|
60
|
-
|
|
66
|
+
Platform.OS === 'android'
|
|
67
|
+
? DyteRNBackgroundTimer.backgroundTimerSetTimeout(timeoutId, timeout)
|
|
68
|
+
: DyteRNBackgroundTimer.setTimeout(timeoutId, timeout);
|
|
61
69
|
return timeoutId;
|
|
62
70
|
}
|
|
63
71
|
clearTimeout(timeoutId) {
|
|
@@ -74,7 +82,9 @@ class BackgroundTimer {
|
|
|
74
82
|
interval: true,
|
|
75
83
|
timeout,
|
|
76
84
|
};
|
|
77
|
-
|
|
85
|
+
Platform.OS === 'android'
|
|
86
|
+
? DyteRNBackgroundTimer.backgroundTimerSetTimeout(intervalId, timeout)
|
|
87
|
+
: DyteRNBackgroundTimer.setTimeout(intervalId, timeout);
|
|
78
88
|
return intervalId;
|
|
79
89
|
}
|
|
80
90
|
clearInterval(intervalId) {
|
|
@@ -26,6 +26,7 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
26
26
|
audioEnabled: boolean;
|
|
27
27
|
videoEnabled: boolean;
|
|
28
28
|
screenShareEnabled: boolean;
|
|
29
|
+
private _pendingScreenShare;
|
|
29
30
|
currentDevices: {
|
|
30
31
|
audio?: MediaDeviceInfo;
|
|
31
32
|
video?: MediaDeviceInfo;
|
|
@@ -38,8 +39,6 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
38
39
|
_handleAppStateChange: (nextAppState: any) => void;
|
|
39
40
|
private configureForeground;
|
|
40
41
|
constructor(localMediaUtils: LocalMediaUtils);
|
|
41
|
-
destructor(): void;
|
|
42
|
-
private handlePermissionErrors;
|
|
43
42
|
private conditionallyRestartAudio;
|
|
44
43
|
private conditionallyRestartVideo;
|
|
45
44
|
private shouldReacquireTrack;
|
|
@@ -63,16 +62,11 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
63
62
|
audio: boolean;
|
|
64
63
|
video: boolean;
|
|
65
64
|
}): Promise<void>;
|
|
66
|
-
private stopAudioTrack;
|
|
67
|
-
private stopVideoTrack;
|
|
68
65
|
private stopScreenShareTracks;
|
|
69
|
-
removeAudioTrack(): void;
|
|
70
|
-
removeVideoTrack(): void;
|
|
71
66
|
removeScreenShareTracks(tracks?: {
|
|
72
67
|
audio?: boolean;
|
|
73
68
|
video?: boolean;
|
|
74
69
|
}): void;
|
|
75
|
-
removeAllTracks(): void;
|
|
76
70
|
private setAudioTrack;
|
|
77
71
|
private setVideoTrack;
|
|
78
72
|
private setScreenShareTracks;
|
|
@@ -86,13 +80,12 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
86
80
|
setAudioDevice(device: MediaDeviceInfo): Promise<void>;
|
|
87
81
|
setVideoDevice(device: MediaDeviceInfo): Promise<void>;
|
|
88
82
|
setSpeakerDevice(device?: MediaDeviceInfo): Promise<void>;
|
|
89
|
-
setDevice(route: MediaDeviceInfo): Promise<
|
|
83
|
+
setDevice(route: MediaDeviceInfo): Promise<void>;
|
|
90
84
|
private oniOSBroadcastStart;
|
|
91
85
|
private oniOSBroadcastStop;
|
|
92
86
|
toggleScreenShare(): Promise<void>;
|
|
93
87
|
enableScreenShare(): Promise<void>;
|
|
94
88
|
disableScreenShare(): Promise<void>;
|
|
95
|
-
destruct(): void;
|
|
96
89
|
getAllDevices(): MediaDeviceInfo[];
|
|
97
90
|
getCurrentDevices(): {
|
|
98
91
|
audio?: MediaDeviceInfo;
|
|
@@ -114,11 +107,16 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
114
107
|
added: MediaDeviceInfo[];
|
|
115
108
|
removed: MediaDeviceInfo[];
|
|
116
109
|
}, forceDeviceChange: boolean): Promise<void>;
|
|
117
|
-
cleanUpTracks(): void;
|
|
118
|
-
destructMediaHandler(): Promise<void>;
|
|
119
110
|
static init(_: any): Promise<LocalMediaHandler>;
|
|
120
111
|
emit(event: keyof typeof MediaEvents, ...args: any[]): boolean;
|
|
121
112
|
on(event: keyof typeof MediaEvents, listener: (...args: any[]) => void): this;
|
|
113
|
+
destruct(): void;
|
|
114
|
+
destructMediaHandler(): Promise<void>;
|
|
115
|
+
removeAllTracks(): void;
|
|
116
|
+
private stopAudioTrack;
|
|
117
|
+
removeAudioTrack(): void;
|
|
118
|
+
private stopVideoTrack;
|
|
119
|
+
removeVideoTrack(): void;
|
|
122
120
|
}
|
|
123
121
|
export interface RNLocalMediaHandler {
|
|
124
122
|
new (): LocalMediaHandler;
|
package/lib/LocalMediaHandler.js
CHANGED
|
@@ -22,7 +22,7 @@ var _LocalMediaHandler_localMediaUtils, _LocalMediaHandler_appState, _LocalMedia
|
|
|
22
22
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
23
23
|
import { EventEmitter } from 'events';
|
|
24
24
|
import LocalMediaUtils from './LocalMediaUtils';
|
|
25
|
-
import { AppState, NativeEventEmitter, NativeModules, Platform, } from 'react-native';
|
|
25
|
+
import { AppState, NativeEventEmitter, NativeModules, PermissionsAndroid, Platform, } from 'react-native';
|
|
26
26
|
import BackgroundTimer from './BackgroundHandler';
|
|
27
27
|
import InCallManger from './NativeAudioManager';
|
|
28
28
|
import { setupPermissions } from './PermissionHandler';
|
|
@@ -47,12 +47,26 @@ function checkIfAudioTrackIsSilent(track) {
|
|
|
47
47
|
class LocalMediaHandler extends EventEmitter {
|
|
48
48
|
configureForeground() {
|
|
49
49
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
if (Platform.OS !== 'android')
|
|
51
|
+
return;
|
|
50
52
|
const val = yield DyteHelper.isForegroundServiceRunning();
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
+
if (!val) {
|
|
54
|
+
if (Platform.Version >= 33) {
|
|
55
|
+
const res = yield PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);
|
|
56
|
+
if (res !== PermissionsAndroid.RESULTS.GRANTED) {
|
|
57
|
+
console.warn('Permission required for screenshare notification');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (Platform.Version >= 26) {
|
|
61
|
+
yield DyteHelper.createNotificationChannel();
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
yield DyteHelper.startService();
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
console.warn('Failed to start foreground service', e);
|
|
68
|
+
}
|
|
53
69
|
}
|
|
54
|
-
if (!val)
|
|
55
|
-
yield DyteHelper.startService();
|
|
56
70
|
});
|
|
57
71
|
}
|
|
58
72
|
constructor(localMediaUtils) {
|
|
@@ -61,8 +75,8 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
61
75
|
_LocalMediaHandler_appState.set(this, void 0);
|
|
62
76
|
_LocalMediaHandler_appStateSubscription.set(this, void 0);
|
|
63
77
|
_LocalMediaHandler_interval.set(this, void 0);
|
|
78
|
+
this._pendingScreenShare = false;
|
|
64
79
|
this._handleAppStateChange = (nextAppState) => {
|
|
65
|
-
// console.log('App state changed to : ', nextAppState);
|
|
66
80
|
if (__classPrivateFieldGet(this, _LocalMediaHandler_appState, "f").match(/inactive|background/) &&
|
|
67
81
|
nextAppState === 'active') {
|
|
68
82
|
BackgroundTimer.clearInterval(__classPrivateFieldGet(this, _LocalMediaHandler_interval, "f"));
|
|
@@ -78,7 +92,9 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
78
92
|
}
|
|
79
93
|
else {
|
|
80
94
|
if (__classPrivateFieldGet(this, _LocalMediaHandler_interval, "f") === null) {
|
|
81
|
-
this.
|
|
95
|
+
if (this.screenShareEnabled || this._pendingScreenShare) {
|
|
96
|
+
this.configureForeground();
|
|
97
|
+
}
|
|
82
98
|
}
|
|
83
99
|
__classPrivateFieldSet(this, _LocalMediaHandler_interval, BackgroundTimer.setInterval(() => { }, 1000), "f");
|
|
84
100
|
__classPrivateFieldSet(this, _LocalMediaHandler_appState, nextAppState, "f");
|
|
@@ -113,15 +129,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
113
129
|
}
|
|
114
130
|
InCallManger.start({});
|
|
115
131
|
}
|
|
116
|
-
destructor() {
|
|
117
|
-
__classPrivateFieldGet(this, _LocalMediaHandler_appStateSubscription, "f").remove();
|
|
118
|
-
broadcastEmitter.removeAllListeners('iOS_BroadcastStarted');
|
|
119
|
-
broadcastEmitter.removeAllListeners('iOS_BroadcastStopped');
|
|
120
|
-
BackgroundTimer.stop();
|
|
121
|
-
}
|
|
122
|
-
handlePermissionErrors(kind, err) {
|
|
123
|
-
// pass
|
|
124
|
-
}
|
|
125
132
|
conditionallyRestartAudio() {
|
|
126
133
|
return __awaiter(this, void 0, void 0, function* () {
|
|
127
134
|
var _a;
|
|
@@ -250,9 +257,8 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
250
257
|
}
|
|
251
258
|
this.setAudioTrack(this.rawAudioTrack);
|
|
252
259
|
this.addMediaStreamTrackListeners(this.audioTrack);
|
|
260
|
+
this.emit('AUDIO_TRACK_CHANGE');
|
|
253
261
|
this.setDevice(this.currentDevices.audio);
|
|
254
|
-
// await InCallManger.chooseAudioRoute(audioDeviceId);
|
|
255
|
-
// console.log('Device selected: ', audioDeviceId);
|
|
256
262
|
/**
|
|
257
263
|
* NOTE(roerohan): Firefox does not show device labels until permissions are granted.
|
|
258
264
|
* So, we need to repopulate the devices once permission is granted.
|
|
@@ -263,10 +269,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
263
269
|
this.emit('DEVICE_CHANGE', {
|
|
264
270
|
device: this.currentDevices.audio,
|
|
265
271
|
});
|
|
266
|
-
/*
|
|
267
|
-
TODO
|
|
268
|
-
callStats.mediaPermission('AUDIO', CallStatsPermissionEnum.ACCEPTED);
|
|
269
|
-
callStats.selectedDevice('AUDIO', this.currentDevices.audio); */
|
|
270
272
|
});
|
|
271
273
|
}
|
|
272
274
|
onVisibilityChange() {
|
|
@@ -305,6 +307,7 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
305
307
|
}
|
|
306
308
|
this.setVideoTrack(this.rawVideoTrack);
|
|
307
309
|
this.addMediaStreamTrackListeners(this.rawVideoTrack);
|
|
310
|
+
this.emit('VIDEO_TRACK_CHANGE');
|
|
308
311
|
}
|
|
309
312
|
if (forceStopTrack) {
|
|
310
313
|
(_b = this.videoTrack) === null || _b === void 0 ? void 0 : _b.stop();
|
|
@@ -469,19 +472,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
469
472
|
}
|
|
470
473
|
});
|
|
471
474
|
}
|
|
472
|
-
stopAudioTrack() {
|
|
473
|
-
var _a, _b;
|
|
474
|
-
(_a = this.audioTrack) === null || _a === void 0 ? void 0 : _a.stop();
|
|
475
|
-
(_b = this.audioTrack) === null || _b === void 0 ? void 0 : _b.release();
|
|
476
|
-
this.audioEnabled = false;
|
|
477
|
-
}
|
|
478
|
-
stopVideoTrack() {
|
|
479
|
-
var _a, _b, _c, _d;
|
|
480
|
-
(_a = this.rawVideoTrack) === null || _a === void 0 ? void 0 : _a.stop();
|
|
481
|
-
(_b = this.videoTrack) === null || _b === void 0 ? void 0 : _b.stop();
|
|
482
|
-
(_c = this.rawVideoTrack) === null || _c === void 0 ? void 0 : _c.release();
|
|
483
|
-
(_d = this.videoTrack) === null || _d === void 0 ? void 0 : _d.release();
|
|
484
|
-
}
|
|
485
475
|
stopScreenShareTracks(tracks = {}) {
|
|
486
476
|
var _a, _b, _c, _d;
|
|
487
477
|
const { audio = true, video = true } = tracks;
|
|
@@ -495,16 +485,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
495
485
|
this.screenShareEnabled = false;
|
|
496
486
|
}
|
|
497
487
|
}
|
|
498
|
-
removeAudioTrack() {
|
|
499
|
-
this.stopAudioTrack();
|
|
500
|
-
this.audioTrack = undefined;
|
|
501
|
-
this.rawAudioTrack = undefined;
|
|
502
|
-
}
|
|
503
|
-
removeVideoTrack() {
|
|
504
|
-
this.stopVideoTrack();
|
|
505
|
-
this.videoTrack = undefined;
|
|
506
|
-
this.rawVideoTrack = undefined;
|
|
507
|
-
}
|
|
508
488
|
removeScreenShareTracks(tracks) {
|
|
509
489
|
var _a;
|
|
510
490
|
(_a = this.screenShareTracks.video) === null || _a === void 0 ? void 0 : _a.removeEventListener('ended', this.onScreenShareEnded);
|
|
@@ -514,11 +494,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
514
494
|
video: undefined,
|
|
515
495
|
};
|
|
516
496
|
}
|
|
517
|
-
removeAllTracks() {
|
|
518
|
-
this.removeAudioTrack();
|
|
519
|
-
this.removeVideoTrack();
|
|
520
|
-
this.removeScreenShareTracks();
|
|
521
|
-
}
|
|
522
497
|
setAudioTrack(audioTrack) {
|
|
523
498
|
if (audioTrack === this.audioTrack) {
|
|
524
499
|
return;
|
|
@@ -660,10 +635,7 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
660
635
|
}
|
|
661
636
|
setAudioDevice(device) {
|
|
662
637
|
return __awaiter(this, void 0, void 0, function* () {
|
|
663
|
-
yield
|
|
664
|
-
this.setupAudioStream(device.deviceId);
|
|
665
|
-
this.emit('AUDIO_TRACK_CHANGE');
|
|
666
|
-
this.emit('DEVICE_CHANGE', { device });
|
|
638
|
+
yield this.setupAudioStream(device.deviceId);
|
|
667
639
|
});
|
|
668
640
|
}
|
|
669
641
|
setVideoDevice(device) {
|
|
@@ -672,8 +644,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
672
644
|
this.removeVideoTrack();
|
|
673
645
|
}
|
|
674
646
|
yield this.setupVideoStream(device.deviceId);
|
|
675
|
-
this.emit('VIDEO_TRACK_CHANGE');
|
|
676
|
-
this.emit('DEVICE_CHANGE', { device });
|
|
677
647
|
});
|
|
678
648
|
}
|
|
679
649
|
setSpeakerDevice(device) {
|
|
@@ -683,7 +653,7 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
683
653
|
}
|
|
684
654
|
setDevice(route) {
|
|
685
655
|
return __awaiter(this, void 0, void 0, function* () {
|
|
686
|
-
|
|
656
|
+
yield __classPrivateFieldGet(this, _LocalMediaHandler_localMediaUtils, "f").chooseAudioRoute(route.deviceId);
|
|
687
657
|
});
|
|
688
658
|
}
|
|
689
659
|
oniOSBroadcastStart() {
|
|
@@ -706,6 +676,12 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
706
676
|
return __awaiter(this, void 0, void 0, function* () {
|
|
707
677
|
if (this.screenShareEnabled && Platform.OS !== 'ios') {
|
|
708
678
|
this.removeScreenShareTracks();
|
|
679
|
+
try {
|
|
680
|
+
yield DyteHelper.stopService();
|
|
681
|
+
}
|
|
682
|
+
catch (e) {
|
|
683
|
+
console.warn('Failed to stop foreground service', e);
|
|
684
|
+
}
|
|
709
685
|
return;
|
|
710
686
|
}
|
|
711
687
|
if (Platform.OS === 'ios' && this.screenShareEnabled) {
|
|
@@ -713,13 +689,21 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
713
689
|
return;
|
|
714
690
|
}
|
|
715
691
|
if (Platform.OS === 'android') {
|
|
716
|
-
|
|
717
|
-
This is because we need to get user permission starting foreground service in Android >=14
|
|
718
|
-
1. createScreenCaptureIntent() -> startForeground()
|
|
719
|
-
*/
|
|
720
|
-
this.setScreenShareTracks(yield LocalMediaUtils.getScreenShareTracks());
|
|
692
|
+
this._pendingScreenShare = true;
|
|
721
693
|
yield this.configureForeground();
|
|
722
|
-
|
|
694
|
+
try {
|
|
695
|
+
this.setScreenShareTracks(yield LocalMediaUtils.getScreenShareTracks());
|
|
696
|
+
this.screenShareEnabled = true;
|
|
697
|
+
}
|
|
698
|
+
catch (e) {
|
|
699
|
+
console.warn('Failed to start screenshare', e);
|
|
700
|
+
this.screenShareEnabled = false;
|
|
701
|
+
yield DyteHelper.stopService();
|
|
702
|
+
this._pendingScreenShare = false;
|
|
703
|
+
}
|
|
704
|
+
finally {
|
|
705
|
+
this._pendingScreenShare = false;
|
|
706
|
+
}
|
|
723
707
|
}
|
|
724
708
|
if (Platform.OS === 'ios') {
|
|
725
709
|
NativeModules.DyteScreensharePickerView.showScreenSharePickerView();
|
|
@@ -736,11 +720,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
736
720
|
yield this.toggleScreenShare();
|
|
737
721
|
});
|
|
738
722
|
}
|
|
739
|
-
destruct() {
|
|
740
|
-
this.removeAllTracks();
|
|
741
|
-
this.removeAllListeners();
|
|
742
|
-
InCallManger.stop(undefined);
|
|
743
|
-
}
|
|
744
723
|
getAllDevices() {
|
|
745
724
|
return __classPrivateFieldGet(this, _LocalMediaHandler_localMediaUtils, "f").availableDevices;
|
|
746
725
|
}
|
|
@@ -813,20 +792,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
813
792
|
}
|
|
814
793
|
});
|
|
815
794
|
}
|
|
816
|
-
cleanUpTracks() {
|
|
817
|
-
var _a, _b, _c, _d;
|
|
818
|
-
(_a = this.audioTrack) === null || _a === void 0 ? void 0 : _a.stop();
|
|
819
|
-
(_b = this.rawAudioTrack) === null || _b === void 0 ? void 0 : _b.stop();
|
|
820
|
-
(_c = this.videoTrack) === null || _c === void 0 ? void 0 : _c.stop();
|
|
821
|
-
(_d = this.rawVideoTrack) === null || _d === void 0 ? void 0 : _d.stop();
|
|
822
|
-
this.destructor();
|
|
823
|
-
}
|
|
824
|
-
destructMediaHandler() {
|
|
825
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
826
|
-
__classPrivateFieldGet(this, _LocalMediaHandler_localMediaUtils, "f").destruct();
|
|
827
|
-
return this.destruct();
|
|
828
|
-
});
|
|
829
|
-
}
|
|
830
795
|
static init(_) {
|
|
831
796
|
return __awaiter(this, void 0, void 0, function* () {
|
|
832
797
|
const localMediaUtils = yield LocalMediaUtils.init();
|
|
@@ -839,6 +804,58 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
839
804
|
on(event, listener) {
|
|
840
805
|
return super.on(event, listener);
|
|
841
806
|
}
|
|
807
|
+
destruct() {
|
|
808
|
+
// TODO: Do not remove native broadcast listeners when going OFF_STAGE in webinar
|
|
809
|
+
// this.#localMediaUtils.destruct();
|
|
810
|
+
if (Platform.OS === 'android')
|
|
811
|
+
__classPrivateFieldGet(this, _LocalMediaHandler_appStateSubscription, "f").remove();
|
|
812
|
+
BackgroundTimer.stop();
|
|
813
|
+
try {
|
|
814
|
+
if (Platform.OS === 'android')
|
|
815
|
+
DyteHelper.stopService();
|
|
816
|
+
}
|
|
817
|
+
catch (_err) { }
|
|
818
|
+
InCallManger.stop(undefined);
|
|
819
|
+
// NOTE: This is a no-op, it's functions are handled in web-core
|
|
820
|
+
// this.destructMediaHandler();
|
|
821
|
+
}
|
|
822
|
+
destructMediaHandler() {
|
|
823
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
824
|
+
this.removeAllTracks();
|
|
825
|
+
this.removeAllListeners();
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
removeAllTracks() {
|
|
829
|
+
this.removeAudioTrack();
|
|
830
|
+
this.removeVideoTrack();
|
|
831
|
+
this.removeScreenShareTracks();
|
|
832
|
+
}
|
|
833
|
+
stopAudioTrack() {
|
|
834
|
+
var _a, _b, _c, _d;
|
|
835
|
+
(_a = this.rawAudioTrack) === null || _a === void 0 ? void 0 : _a.stop();
|
|
836
|
+
(_b = this.audioTrack) === null || _b === void 0 ? void 0 : _b.stop();
|
|
837
|
+
(_c = this.rawAudioTrack) === null || _c === void 0 ? void 0 : _c.release();
|
|
838
|
+
(_d = this.audioTrack) === null || _d === void 0 ? void 0 : _d.release();
|
|
839
|
+
this.audioEnabled = false;
|
|
840
|
+
}
|
|
841
|
+
removeAudioTrack() {
|
|
842
|
+
this.stopAudioTrack();
|
|
843
|
+
this.audioTrack = undefined;
|
|
844
|
+
this.rawAudioTrack = undefined;
|
|
845
|
+
}
|
|
846
|
+
stopVideoTrack() {
|
|
847
|
+
var _a, _b, _c, _d;
|
|
848
|
+
(_a = this.rawVideoTrack) === null || _a === void 0 ? void 0 : _a.stop();
|
|
849
|
+
(_b = this.videoTrack) === null || _b === void 0 ? void 0 : _b.stop();
|
|
850
|
+
(_c = this.rawVideoTrack) === null || _c === void 0 ? void 0 : _c.release();
|
|
851
|
+
(_d = this.videoTrack) === null || _d === void 0 ? void 0 : _d.release();
|
|
852
|
+
this.videoEnabled = false;
|
|
853
|
+
}
|
|
854
|
+
removeVideoTrack() {
|
|
855
|
+
this.stopVideoTrack();
|
|
856
|
+
this.videoTrack = undefined;
|
|
857
|
+
this.rawVideoTrack = undefined;
|
|
858
|
+
}
|
|
842
859
|
}
|
|
843
860
|
_LocalMediaHandler_localMediaUtils = new WeakMap(), _LocalMediaHandler_appState = new WeakMap(), _LocalMediaHandler_appStateSubscription = new WeakMap(), _LocalMediaHandler_interval = new WeakMap();
|
|
844
861
|
export default LocalMediaHandler;
|
package/lib/LocalMediaUtils.js
CHANGED
|
@@ -120,7 +120,6 @@ class LocalMediaUtils {
|
|
|
120
120
|
return Object.assign(Object.assign({}, audioDeviceProps), { deviceId: audioDevice, label: audioDevice, kind: 'audioinput' });
|
|
121
121
|
})
|
|
122
122
|
.filter((audioDevice) => audioDevice.connected);
|
|
123
|
-
// console.log('Resp: ', JSON.stringify(resp, null, 2));
|
|
124
123
|
return resp;
|
|
125
124
|
});
|
|
126
125
|
}
|
|
@@ -178,7 +177,6 @@ class LocalMediaUtils {
|
|
|
178
177
|
* is made: https://github.com/microsoft/TypeScript/issues/33232
|
|
179
178
|
*/
|
|
180
179
|
const stream = (yield mediaDevices.getDisplayMedia());
|
|
181
|
-
// console.log('Screenshare stream: ', stream.getVideoTracks());
|
|
182
180
|
return {
|
|
183
181
|
video: stream.getVideoTracks()[0],
|
|
184
182
|
audio: stream.getAudioTracks()[0],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudflare/realtimekit-react-native",
|
|
3
|
-
"version": "0.1.2-staging.
|
|
3
|
+
"version": "0.1.2-staging.11",
|
|
4
4
|
"description": "Cloudflare RealtimeKit SDK for react native",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"author": "Cloudflare",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"private": false,
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@cloudflare/realtimekit": "1.0.
|
|
28
|
+
"@cloudflare/realtimekit": "1.0.2",
|
|
29
29
|
"events": "^3.3.0",
|
|
30
30
|
"fast-base64-decode": "1.0.0",
|
|
31
31
|
"node-libs-react-native": "^1.2.1",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"android"
|
|
39
39
|
],
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@cloudflare/react-native-webrtc": "114.0.
|
|
41
|
+
"@cloudflare/react-native-webrtc": "~114.0.18",
|
|
42
42
|
"@expo/config-plugins": "*",
|
|
43
43
|
"react": "*",
|
|
44
44
|
"react-native": "*"
|