@cloudflare/realtimekit-react-native 0.1.2-staging.1 → 0.1.2-staging.10

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.
@@ -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 | ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA | ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
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 = "DyteNotificationChannel";
26
- private static final String CHANNEL_NAME = "Ongoing Conference Notifications";
27
- private static final String CHANNEL_DESC = "Ongoing Conference Notifications";
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("Ongoing Meeting")
87
- .setContentText("Tap to return to the meeting")
88
- .setPriority(NotificationCompat.PRIORITY_DEFAULT)
86
+ .setContentTitle("Screen Share")
87
+ .setContentText("You are sharing your screen")
88
+ .setPriority(NotificationCompat.PRIORITY_LOW)
89
89
  .setContentIntent(pendingIntent)
90
- .setOngoing(true)
91
- .setWhen(System.currentTimeMillis())
92
- .setUsesChronometer(true)
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
  }
@@ -549,6 +549,11 @@ RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
549
549
  {
550
550
  // NSLog(@"👉 Checking if Bluetooth device is connected");
551
551
  NSMutableArray *devices = [NSMutableArray array];
552
+ NSError *error = nil;
553
+ [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord
554
+ withOptions:AVAudioSessionCategoryOptionAllowBluetooth
555
+ error:&error];
556
+ [[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:nil];
552
557
  AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];
553
558
  for (AVAudioSessionPortDescription* desc in [route outputs]) {
554
559
  // NSLog(@"🧑‍💻 Bluetooth Desc: %@", desc);
@@ -558,6 +563,20 @@ RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
558
563
  [devices addObject:[desc portName]];
559
564
  }
560
565
  }
566
+
567
+ // If no Bluetooth device found in current route, check available outputs
568
+ if (devices.count == 0) {
569
+ NSArray<AVAudioSessionPortDescription *> *inputs = [route inputs];
570
+
571
+ // Check if Bluetooth is available in inputs (for headsets that function as both input and output)
572
+ for (AVAudioSessionPortDescription* desc in inputs) {
573
+ if ([[desc portType] isEqualToString:AVAudioSessionPortBluetoothHFP] ||
574
+ [[desc portType] isEqualToString:AVAudioSessionPortBluetoothLE]) {
575
+ [devices addObject:[desc portName]];
576
+ }
577
+ }
578
+ }
579
+
561
580
  // NSLog(@"🧑‍💻 Bluetooth Devices %@", devices);
562
581
  if (!devices || !devices.count){
563
582
  resolve(@NO);
@@ -1018,16 +1037,7 @@ RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
1018
1037
  // NSLog(@"🧑‍💻 RNInCallManager.AudioRouteChange.Reason: CategoryChange. category=%@ mode=%@", self->_audioSession.category, self->_audioSession.mode);
1019
1038
  break;
1020
1039
  case AVAudioSessionRouteChangeReasonOverride:
1021
- @try {
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
- }
1040
+ // NSLog(@"🧑‍💻 RNInCallManager.AudioRouteChange.Reason: Override");
1031
1041
  break;
1032
1042
  case AVAudioSessionRouteChangeReasonWakeFromSleep:
1033
1043
  // NSLog(@"RNInCallManager.AudioRouteChange.Reason: WakeFromSleep");
@@ -1,6 +1,6 @@
1
1
  import ReplayKit
2
2
 
3
- open class DyteScreenshareHandler: RPBroadcastSampleHandler {
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 DyteScreenshareHandler {
69
+ private extension RTKScreenshareHandler {
72
70
 
73
71
  func setupConnection() {
74
72
  clientConnection?.didClose = { [weak self] error in
@@ -13,7 +13,9 @@ class BackgroundTimer {
13
13
  delete this.callbacks[id];
14
14
  }
15
15
  else {
16
- DyteRNBackgroundTimer.backgroundTimerSetTimeout(id, this.callbacks[id].timeout);
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 DyteRNBackgroundTimer.start(delay);
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 DyteRNBackgroundTimer.stop();
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
- DyteRNBackgroundTimer.setTimeout(timeoutId, timeout);
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
- DyteRNBackgroundTimer.backgroundTimerSetTimeout(intervalId, timeout);
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<any>;
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,19 @@ 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
+ cleanUpTracks(): void;
116
+ destructor(): void;
117
+ removeAllTracks(): void;
118
+ private stopAudioTrack;
119
+ removeAudioTrack(): void;
120
+ private stopVideoTrack;
121
+ removeVideoTrack(): void;
122
+ removeAllListeners(event?: keyof typeof MediaEvents): this;
122
123
  }
123
124
  export interface RNLocalMediaHandler {
124
125
  new (): LocalMediaHandler;
@@ -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 (Platform.Version >= 26) {
52
- yield DyteHelper.createNotificationChannel();
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.configureForeground();
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 __classPrivateFieldGet(this, _LocalMediaHandler_localMediaUtils, "f").chooseAudioRoute(device.deviceId);
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
- return yield __classPrivateFieldGet(this, _LocalMediaHandler_localMediaUtils, "f").chooseAudioRoute(route.deviceId);
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
- /* getDisplayMedia() needs to be called before configureForeground()
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
- this.screenShareEnabled = true;
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,74 @@ class LocalMediaHandler extends EventEmitter {
839
804
  on(event, listener) {
840
805
  return super.on(event, listener);
841
806
  }
807
+ destruct() {
808
+ this.destructMediaHandler();
809
+ }
810
+ destructMediaHandler() {
811
+ return __awaiter(this, void 0, void 0, function* () {
812
+ this.removeAllTracks();
813
+ this.removeAllListeners();
814
+ this.cleanUpTracks();
815
+ __classPrivateFieldGet(this, _LocalMediaHandler_localMediaUtils, "f").destruct();
816
+ try {
817
+ if (Platform.OS === 'android')
818
+ yield DyteHelper.stopService();
819
+ }
820
+ catch (_err) { }
821
+ InCallManger.stop(undefined);
822
+ });
823
+ }
824
+ cleanUpTracks() {
825
+ var _a, _b, _c, _d;
826
+ (_a = this.audioTrack) === null || _a === void 0 ? void 0 : _a.stop();
827
+ (_b = this.rawAudioTrack) === null || _b === void 0 ? void 0 : _b.stop();
828
+ (_c = this.videoTrack) === null || _c === void 0 ? void 0 : _c.stop();
829
+ (_d = this.rawVideoTrack) === null || _d === void 0 ? void 0 : _d.stop();
830
+ this.destructor();
831
+ }
832
+ destructor() {
833
+ if (Platform.OS === 'android')
834
+ __classPrivateFieldGet(this, _LocalMediaHandler_appStateSubscription, "f").remove();
835
+ // TODO: Remove native broadcast listeners for group_call & not for webinar
836
+ BackgroundTimer.stop();
837
+ }
838
+ removeAllTracks() {
839
+ this.removeAudioTrack();
840
+ this.removeVideoTrack();
841
+ this.removeScreenShareTracks();
842
+ }
843
+ stopAudioTrack() {
844
+ var _a, _b;
845
+ (_a = this.audioTrack) === null || _a === void 0 ? void 0 : _a.stop();
846
+ (_b = this.audioTrack) === null || _b === void 0 ? void 0 : _b.release();
847
+ this.audioEnabled = false;
848
+ }
849
+ removeAudioTrack() {
850
+ this.stopAudioTrack();
851
+ this.audioTrack = undefined;
852
+ this.rawAudioTrack = undefined;
853
+ }
854
+ stopVideoTrack() {
855
+ var _a, _b, _c, _d;
856
+ (_a = this.rawVideoTrack) === null || _a === void 0 ? void 0 : _a.stop();
857
+ (_b = this.videoTrack) === null || _b === void 0 ? void 0 : _b.stop();
858
+ (_c = this.rawVideoTrack) === null || _c === void 0 ? void 0 : _c.release();
859
+ (_d = this.videoTrack) === null || _d === void 0 ? void 0 : _d.release();
860
+ }
861
+ removeVideoTrack() {
862
+ this.stopVideoTrack();
863
+ this.videoTrack = undefined;
864
+ this.rawVideoTrack = undefined;
865
+ }
866
+ removeAllListeners(event) {
867
+ if (event === 'SCREENSHARE_TRACK_CHANGE' ||
868
+ event === 'DEVICE_LIST_UPDATED' ||
869
+ event === 'DEVICE_CHANGE' ||
870
+ !event) {
871
+ return null;
872
+ }
873
+ return super.removeAllListeners(event);
874
+ }
842
875
  }
843
876
  _LocalMediaHandler_localMediaUtils = new WeakMap(), _LocalMediaHandler_appState = new WeakMap(), _LocalMediaHandler_appStateSubscription = new WeakMap(), _LocalMediaHandler_interval = new WeakMap();
844
877
  export default LocalMediaHandler;
@@ -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.1",
3
+ "version": "0.1.2-staging.10",
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.1",
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.16",
41
+ "@cloudflare/react-native-webrtc": "~114.0.18",
42
42
  "@expo/config-plugins": "*",
43
43
  "react": "*",
44
44
  "react-native": "*"