@daily-co/react-native-daily-js 0.44.0 → 0.46.0

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/README.md CHANGED
@@ -6,7 +6,7 @@ The Daily JavaScript library for React Native.
6
6
 
7
7
  This package introduces some constraints on what OS/SDK versions your project can support:
8
8
 
9
- - **iOS**: Deployment target >= 11.0
9
+ - **iOS**: Deployment target >= 12.0
10
10
  - **Android**: `minSdkVersion` >= 24
11
11
 
12
12
  ## Installation
@@ -24,12 +24,14 @@ Then, follow the below steps to set up your native project on each platform. **N
24
24
 
25
25
  ### iOS
26
26
 
27
- Update the `platform` in your `Podfile`, since `@daily-co/react-native-webrtc` only works on iOS 11 and above:
27
+ Update the `platform` in your `Podfile`, since `@daily-co/react-native-webrtc` only works on iOS 12 and above:
28
28
 
29
29
  ```ruby
30
- platform :ios, '11.0'
30
+ platform :ios, '12.0'
31
31
  ```
32
32
 
33
+ > If you wish to **send screen share** from iOS, it only works on **iOS 14** and above. Therefore, in this case, please switch to using iOS 14.0 instead of iOS 12.0.
34
+
33
35
  Then run:
34
36
 
35
37
  ```bash
@@ -72,6 +74,11 @@ If you view the raw file contents of `Info.plist`, it should look like this:
72
74
  </dict>
73
75
  ```
74
76
 
77
+ #### Screen sharing on iOS
78
+
79
+ To use the screen sharing functionality on iOS, you'll need to do a few manual steps to set up Daily's [React Native Screen Share Extension framework](https://github.com/daily-co/rn-screen-share-extension/) (already included in `react-native-daily-js`).
80
+ Please refer to its README for a detailed walkthrough.
81
+
75
82
  ### Android
76
83
 
77
84
  Add the following to `AndroidManifest.xml`:
@@ -90,10 +97,12 @@ Add the following to `AndroidManifest.xml`:
90
97
 
91
98
  <application>
92
99
  // ...
93
- <service android:name="com.daily.reactlibrary.DailyOngoingMeetingForegroundService"/>
100
+ <service android:name="com.daily.reactlibrary.DailyOngoingMeetingForegroundService" android:foregroundServiceType="mediaProjection"/>
94
101
  </application>
95
102
  ```
96
103
 
104
+ > Note: above, `foregroundServiceType` is only needed if you wish to do screen sharing.
105
+
97
106
  Update your `minSdkVersion` in your top-level `build.gradle` file:
98
107
 
99
108
  ```groovy
package/dist/index.js CHANGED
@@ -39,10 +39,13 @@ var react_native_background_timer_1 = __importDefault(require("react-native-back
39
39
  var react_native_1 = require("react-native");
40
40
  var DailyNativeUtils = react_native_1.NativeModules.DailyNativeUtils, WebRTCModule = react_native_1.NativeModules.WebRTCModule;
41
41
  var webRTCEventEmitter = new react_native_1.NativeEventEmitter(WebRTCModule);
42
+ var dailyNativeUtilsEventEmitter = new react_native_1.NativeEventEmitter(DailyNativeUtils);
42
43
  var hasAudioFocus;
43
44
  var appState;
44
45
  var audioFocusChangeListeners = new Set();
45
46
  var appActiveStateChangeListeners = new Set();
47
+ var systemScreenCaptureStopListeners = new Set();
48
+ var systemScreenCaptureStartCallback;
46
49
  function setupEventListeners() {
47
50
  // audio focus: used by daily-js to auto-mute mic, for instance
48
51
  if (react_native_1.Platform.OS === 'android') {
@@ -71,6 +74,22 @@ function setupEventListeners() {
71
74
  appActiveStateChangeListeners.forEach(function (listener) { return listener(isActive); });
72
75
  }
73
76
  });
77
+ if (react_native_1.Platform.OS === 'ios') {
78
+ // screen capture stop: used to synchronize JS screen sharing state with iOS
79
+ // system screen capture state, which can be controlled outside the app via
80
+ // the control center or by tapping the notification in the corner.
81
+ dailyNativeUtilsEventEmitter.addListener('EventSystemScreenCaptureStop', function () {
82
+ systemScreenCaptureStopListeners.forEach(function (listener) { return listener(); });
83
+ });
84
+ // when we invoke to start the screen share, we first invoke to start the screen capture
85
+ // and add the listener, so we are only going to start the screen share if the capture has started
86
+ // that is why we just need a single callback
87
+ dailyNativeUtilsEventEmitter.addListener('EventSystemScreenCaptureStart', function () {
88
+ if (systemScreenCaptureStartCallback) {
89
+ systemScreenCaptureStartCallback();
90
+ }
91
+ });
92
+ }
74
93
  }
75
94
  function setupGlobals() {
76
95
  // WebRTC APIs + global `window` object
@@ -96,7 +115,7 @@ function setupGlobals() {
96
115
  return react_native_background_timer_1.default.setTimeout(fn, ms);
97
116
  };
98
117
  }
99
- global.DailyNativeUtils = __assign(__assign({}, DailyNativeUtils), { setAudioMode: WebRTCModule.setDailyAudioMode, setAudioDevice: WebRTCModule.setAudioDevice, getAudioDevice: WebRTCModule.getAudioDevice, enableNoOpRecordingEnsuringBackgroundContinuity: WebRTCModule.enableNoOpRecordingEnsuringBackgroundContinuity, addAudioFocusChangeListener: function (listener) {
118
+ global.DailyNativeUtils = __assign(__assign({}, DailyNativeUtils), { isIOS: react_native_1.Platform.OS === 'ios', isAndroid: react_native_1.Platform.OS === 'android', setAudioMode: WebRTCModule.setDailyAudioMode, setAudioDevice: WebRTCModule.setAudioDevice, getAudioDevice: WebRTCModule.getAudioDevice, enableNoOpRecordingEnsuringBackgroundContinuity: WebRTCModule.enableNoOpRecordingEnsuringBackgroundContinuity, addAudioFocusChangeListener: function (listener) {
100
119
  audioFocusChangeListeners.add(listener);
101
120
  }, removeAudioFocusChangeListener: function (listener) {
102
121
  audioFocusChangeListeners.delete(listener);
@@ -104,6 +123,12 @@ function setupGlobals() {
104
123
  appActiveStateChangeListeners.add(listener);
105
124
  }, removeAppActiveStateChangeListener: function (listener) {
106
125
  appActiveStateChangeListeners.delete(listener);
126
+ }, addSystemScreenCaptureStopListener: function (listener) {
127
+ systemScreenCaptureStopListeners.add(listener);
128
+ }, removeSystemScreenCaptureStopListener: function (listener) {
129
+ systemScreenCaptureStopListeners.delete(listener);
130
+ }, setSystemScreenCaptureStartCallback: function (listener) {
131
+ systemScreenCaptureStartCallback = listener;
107
132
  }, platform: react_native_1.Platform });
108
133
  }
109
134
  setupEventListeners();
@@ -1,5 +1,5 @@
1
- #import <React/RCTBridgeModule.h>
1
+ #import <React/RCTEventEmitter.h>
2
2
 
3
- @interface DailyNativeUtils : NSObject <RCTBridgeModule>
3
+ @interface DailyNativeUtils : RCTEventEmitter
4
4
 
5
5
  @end
@@ -1,6 +1,16 @@
1
1
  #import "DailyNativeUtils.h"
2
2
  #import <AVFoundation/AVFoundation.h>
3
3
  #import <sys/utsname.h>
4
+ #import <ReplayKit/RPBroadcast.h>
5
+ #import <React/RCTUtils.h>
6
+ #import <React/RCTLog.h>
7
+
8
+ // Notification from extension
9
+ static NSString *const NotificationScreenCaptureStoppedBySystemUIOrError = @"ScreenCaptureStoppedBySystemUIOrError";
10
+ static NSString *const NotificationScreenCaptureExtensionStarted = @"ScreenCaptureExtensionStarted";
11
+ // Event to JS layer
12
+ static NSString *const EventSystemScreenCaptureStop = @"EventSystemScreenCaptureStop";
13
+ static NSString *const EventSystemScreenCaptureStart = @"EventSystemScreenCaptureStart";
4
14
 
5
15
  @interface DailyNativeUtils()
6
16
 
@@ -17,6 +27,32 @@ RCT_EXPORT_MODULE()
17
27
  {
18
28
  if (self = [super init]) {
19
29
  _requestersKeepingDeviceAwake = [NSMutableSet set];
30
+
31
+ // The “Darwin” notification center distributes notifications across the whole system!
32
+ // This means you can send and receive notifications between different apps, and/or an app and its extensions.
33
+ // Register for screen capture stopped notification.
34
+ CFNotificationCenterRef notificationCenter = CFNotificationCenterGetDarwinNotifyCenter();
35
+ CFNotificationCenterAddObserver(notificationCenter,
36
+ (__bridge const void *)(self),
37
+ handleDarwinNotification,
38
+ (__bridge CFStringRef)(NotificationScreenCaptureStoppedBySystemUIOrError),
39
+ NULL,
40
+ CFNotificationSuspensionBehaviorDeliverImmediately);
41
+ [[NSNotificationCenter defaultCenter] addObserver:self
42
+ selector:@selector(handleNotificationScreenCaptureStoppedBySystemUIOrError)
43
+ name:NotificationScreenCaptureStoppedBySystemUIOrError
44
+ object:nil];
45
+ // Adding observer so we can be aware when the screen capture has started
46
+ CFNotificationCenterAddObserver(notificationCenter,
47
+ (__bridge const void *)(self),
48
+ handleDarwinNotification,
49
+ (__bridge CFStringRef)(NotificationScreenCaptureExtensionStarted),
50
+ NULL,
51
+ CFNotificationSuspensionBehaviorDeliverImmediately);
52
+ [[NSNotificationCenter defaultCenter] addObserver:self
53
+ selector:@selector(handleNotificationScreenCaptureExtensionStarted)
54
+ name:NotificationScreenCaptureExtensionStarted
55
+ object:nil];
20
56
  }
21
57
  return self;
22
58
  }
@@ -26,6 +62,12 @@ RCT_EXPORT_MODULE()
26
62
  return NO;
27
63
  }
28
64
 
65
+
66
+ - (NSArray<NSString *> *)supportedEvents
67
+ {
68
+ return @[EventSystemScreenCaptureStop, EventSystemScreenCaptureStart];
69
+ }
70
+
29
71
  #pragma mark Public
30
72
 
31
73
  RCT_EXPORT_METHOD(setKeepDeviceAwake:(BOOL)keepDeviceAwake onBehalfOfRequester:(nonnull NSString *)requesterId)
@@ -50,6 +92,66 @@ RCT_REMAP_METHOD(getDeviceCode,
50
92
  encoding:NSUTF8StringEncoding]);
51
93
  }
52
94
 
95
+ //We are implementing here basically the same approach that react-native-webrtc did:
96
+ //https://github.com/daily-co/react-native-webrtc/blob/main/ios/RCTWebRTC/ScreenCapturePickerViewManager.m
97
+ //The difference is, with this approach, we don't need the user to create a screen and add in the app somewhere
98
+ //we are only invoking this method and creating the screen whe the user invokes to startScreenShare.
99
+ RCT_EXPORT_METHOD(presentSystemScreenCapturePrompt)
100
+ {
101
+ dispatch_async(dispatch_get_main_queue(), ^{
102
+ NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
103
+ NSString *screenCaptureExtensionBundleIdentifier = infoDictionary[@"DailyScreenCaptureExtensionBundleIdentifier"];
104
+
105
+ // Simulate a click on a RPSystemBroadcastPickerView. This is ugly, but it's
106
+ // the only way to programmatically trigger the system screen capture
107
+ // prompt (RPBroadcastActivityViewController doesn't do what I expected it
108
+ // to: https://stackoverflow.com/questions/65658319/replaykit-broadcast-upload-extension-service-not-found)
109
+
110
+ RPSystemBroadcastPickerView *screenCaptureButton = [[RPSystemBroadcastPickerView alloc] init];
111
+ screenCaptureButton.preferredExtension = screenCaptureExtensionBundleIdentifier;
112
+ screenCaptureButton.showsMicrophoneButton = false;
113
+ screenCaptureButton.userInteractionEnabled = false;
114
+
115
+ // Code taken from ScreenCapturePickerViewManager
116
+ // Simulate a click
117
+ UIButton *btn = nil;
118
+
119
+ for (UIView *subview in ((RPSystemBroadcastPickerView *)screenCaptureButton).subviews) {
120
+ if ([subview isKindOfClass:[UIButton class]]) {
121
+ btn = (UIButton *)subview;
122
+ }
123
+ }
124
+ if (btn != nil) {
125
+ [btn sendActionsForControlEvents:UIControlEventTouchUpInside];
126
+ }
127
+ else {
128
+ RCTLogError(@"RPSystemBroadcastPickerView button not found");
129
+ }
130
+ });
131
+ }
132
+
133
+ RCT_EXPORT_METHOD(requestStopSystemScreenCapture)
134
+ {
135
+ dispatch_async(dispatch_get_main_queue(), ^{
136
+ // The “Darwin” notification center distributes notifications across the whole system!
137
+ // This means you can send and receive notifications between different apps, and/or an app and its extensions.
138
+ // Register for screen capture stopped notification.
139
+ CFNotificationCenterRef notification = CFNotificationCenterGetDarwinNotifyCenter ();
140
+ CFNotificationCenterPostNotification(notification, (__bridge CFStringRef)(@"MustStopScreenCapture"), NULL, NULL, YES);
141
+ });
142
+ }
143
+
144
+ RCT_REMAP_METHOD(isScreenBeingCaptured,
145
+ withResolver:(RCTPromiseResolveBlock)resolve
146
+ withRejecter:(RCTPromiseRejectBlock)reject)
147
+ {
148
+ if (@available(iOS 11.0, *)) {
149
+ resolve(@(UIScreen.mainScreen.isCaptured));
150
+ } else {
151
+ resolve(false);
152
+ }
153
+ }
154
+
53
155
  #pragma mark Private
54
156
 
55
157
  + (void)dispatchSyncOnMain:(void (^)(void))block
@@ -68,4 +170,29 @@ RCT_REMAP_METHOD(getDeviceCode,
68
170
  [[UIApplication sharedApplication] setIdleTimerDisabled:disableIdleTimer];
69
171
  }
70
172
 
173
+ // Translate Darwin notification to NSNotification so it can be used in
174
+ // Objective-C class. Based on approach taken by MMWormhole and others.
175
+ void handleDarwinNotification(CFNotificationCenterRef center,
176
+ void * observer,
177
+ CFStringRef name,
178
+ void const * object,
179
+ CFDictionaryRef userInfo) {
180
+ NSString *identifier = (__bridge NSString *)name;
181
+ [[NSNotificationCenter defaultCenter] postNotificationName:identifier
182
+ object:nil
183
+ userInfo:nil];
184
+ }
185
+
186
+ // Technically this notification tells us that the screen capture stopped
187
+ // *either* via the system UI or due to an error, but here let's collapse these
188
+ // cases into one event, so that the JS client can "sync" to the fact that the
189
+ // screen capture occurred outside of its control.
190
+ - (void)handleNotificationScreenCaptureStoppedBySystemUIOrError {
191
+ [self sendEventWithName:EventSystemScreenCaptureStop body:nil];
192
+ }
193
+
194
+ - (void)handleNotificationScreenCaptureExtensionStarted {
195
+ [self sendEventWithName:EventSystemScreenCaptureStart body:nil];
196
+ }
197
+
71
198
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daily-co/react-native-daily-js",
3
- "version": "0.44.0",
3
+ "version": "0.46.0",
4
4
  "description": "React Native library for making video calls using Daily",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -26,7 +26,7 @@
26
26
  "baseUrl": "https://github.com/daily-co/react-native-daily-js"
27
27
  },
28
28
  "dependencies": {
29
- "@daily-co/daily-js": "^0.46.0",
29
+ "@daily-co/daily-js": "^0.48.0",
30
30
  "@types/react-native-background-timer": "^2.0.0",
31
31
  "react-native-url-polyfill": "^1.1.2"
32
32
  },
@@ -15,13 +15,14 @@ Pod::Spec.new do |s|
15
15
  # optional - use expanded license entry instead:
16
16
  # s.license = { :type => "MIT", :file => "LICENSE" }
17
17
  s.authors = { "Paul Kompfner" => "paul@daily.co" }
18
- s.platforms = { :ios => "9.0" }
18
+ s.platforms = { :ios => "12.0" }
19
19
  s.source = { :git => "https://github.com/daily-co/react-native-daily-js.git", :tag => "#{s.version}" }
20
20
 
21
21
  s.source_files = "ios/**/*.{h,c,m,swift}"
22
22
  s.requires_arc = true
23
23
 
24
24
  s.dependency "React-Core"
25
+ s.dependency "ReactNativeDailyJSScreenShareExtension", "0.0.1"
25
26
  # ...
26
27
  # s.dependency "..."
27
28
  end
@@ -10,6 +10,7 @@ import {
10
10
  MediaStreamTrack,
11
11
  MediaDeviceInfo,
12
12
  MediaTrackConstraints,
13
+ MediaStream,
13
14
  } from '@daily-co/react-native-webrtc';
14
15
 
15
16
  import RTCRtpEncodingParameters from '@daily-co/react-native-webrtc/lib/typescript/RTCRtpEncodingParameters';
@@ -61,6 +62,8 @@ export type DailyEvent =
61
62
  | 'transcription-stopped'
62
63
  | 'transcription-error'
63
64
  | 'app-message'
65
+ | 'local-screen-share-started'
66
+ | 'local-screen-share-stopped'
64
67
  | 'active-speaker-change'
65
68
  | 'network-quality-change'
66
69
  | 'network-connection'
@@ -114,6 +117,7 @@ export type DailyFatalErrorType =
114
117
  | 'connection-error';
115
118
 
116
119
  export type DailyNonFatalErrorType =
120
+ | 'screen-share-error'
117
121
  | 'remote-media-player-error'
118
122
  | 'live-streaming-warning'
119
123
  | 'meeting-session-data-error';
@@ -164,6 +168,22 @@ export interface CamSimulcastEncoding {
164
168
  scaleResolutionDownBy?: number;
165
169
  }
166
170
 
171
+ /* These types are not defined inside react-native-webrtc, so we need to define them here in order to use */
172
+ type RTCIceTransportPolicy = 'all' | 'relay';
173
+ type RTCIceCredentialType = 'password';
174
+ interface RTCIceServer {
175
+ credential?: string;
176
+ credentialType?: RTCIceCredentialType;
177
+ urls: string | string[];
178
+ username?: string;
179
+ }
180
+
181
+ export interface DailyIceConfig {
182
+ iceServers?: RTCIceServer[];
183
+ placement?: 'front' | 'back' | 'replace';
184
+ iceTransportPolicy?: RTCIceTransportPolicy;
185
+ }
186
+
167
187
  export interface DailyAdvancedConfig {
168
188
  camSimulcastEncodings?: CamSimulcastEncoding[];
169
189
  v2CamAndMic?: boolean;
@@ -173,6 +193,8 @@ export interface DailyAdvancedConfig {
173
193
  userMediaVideoConstraints?: MediaTrackConstraints;
174
194
  preferH264ForCam?: boolean;
175
195
  h264Profile?: string;
196
+ proxyUrl?: string;
197
+ iceConfig?: DailyIceConfig;
176
198
  }
177
199
 
178
200
  export interface DailyReactNativeConfig {
@@ -229,6 +251,7 @@ export interface DailyParticipantPermissions {
229
251
  | 'customAudio'
230
252
  >
231
253
  | boolean;
254
+ canAdmin: Set<'participants' | 'streaming' | 'transcription'> | boolean;
232
255
  }
233
256
 
234
257
  export type DailyParticipantPermissionsUpdate = {
@@ -345,6 +368,13 @@ export interface DailyDeviceInfos {
345
368
  speaker: {} | MediaDeviceInfo;
346
369
  }
347
370
 
371
+ export interface DailyStartScreenShare {
372
+ //RN does not support any displayMediaOptions, that is why we have not added the definition here
373
+ screenVideoSendSettings?:
374
+ | DailyVideoSendSettings
375
+ | DailyScreenVideoSendSettingsPreset;
376
+ }
377
+
348
378
  export interface DailyNetworkStats {
349
379
  quality: number;
350
380
  stats: {
@@ -418,6 +448,12 @@ interface DailyVideoSendSettings {
418
448
  };
419
449
  }
420
450
 
451
+ export type DailyScreenVideoSendSettingsPreset =
452
+ | 'default-screen-video'
453
+ | 'detail-optimized'
454
+ | 'motion-optimized'
455
+ | 'motion-and-detail-balanced';
456
+
421
457
  export interface DailyPendingRoomInfo {
422
458
  roomUrlPendingJoin: string;
423
459
  }
@@ -1160,6 +1196,8 @@ export interface DailyCall {
1160
1196
  stopTranscription(): void;
1161
1197
  preAuth(properties?: DailyCallOptions): Promise<{ access: DailyAccess }>;
1162
1198
  load(properties?: DailyLoadOptions): Promise<void>;
1199
+ startScreenShare(properties?: DailyStartScreenShare): void;
1200
+ stopScreenShare(): void;
1163
1201
  getNetworkStats(): Promise<DailyNetworkStats>;
1164
1202
  getCpuLoadStats(): Promise<DailyCpuLoadStats>;
1165
1203
  updateSendSettings(settings: DailySendSettings): Promise<DailySendSettings>;
@@ -1168,6 +1206,8 @@ export interface DailyCall {
1168
1206
  setSubscribeToTracksAutomatically(enabled: boolean): DailyCall;
1169
1207
  enumerateDevices(): Promise<{ devices: MediaDeviceInfo[] }>;
1170
1208
  sendAppMessage(data: any, to?: string): DailyCall;
1209
+ setProxyUrl(proxyUrl?: string): DailyCall;
1210
+ setIceConfig(iceConfig?: DailyIceConfig): DailyCall;
1171
1211
  meetingSessionState(): DailyMeetingSessionState;
1172
1212
  setMeetingSessionData(
1173
1213
  data: unknown,