Skip to content

Commit c10087e

Browse files
davidliumtdxcsaghul
authored
Merge upstream 124.0.4 into master (#16)
* ios: add support for external cameras on iPad * ci: remove flipper from gumtestapp (react-native-webrtc#1608) These were causing build errors recently, and were generally unneeded anyways. * pc: align createDataChannel with standard - Throw TypeError if no argument passed - Stringify the label Fixes: react-native-webrtc#1605 * android: report actual size in camera MediaStreamTrack settings (react-native-webrtc#1598) * ios: fix exception in iOS 17+ w/ Xcode 15.4 * android: remove no longer used replace rule from manifest (react-native-webrtc#1609) * sender: fix serializing RTCRtpSendParameters It's possible for user code to replace encodings entirely. Thus, the resulting array will not have RTCRtpEncodingParameters object instances, but plain objects. Handle it by deep-cloning the objects with JSON.parse(JSON.stringify(x)) since that will take care of appropriately serializing them, no matter the type. * misc: make serialization more resilient Don't directly call toJSON, but rather rely on JSON serialization to do it when cloning. * release 124.0.4 89557ca misc: make serialization more resilient ( Saúl Ibarra Corretgé 2024-08-14 11:53:32 +0200) 6cfedd7 sender: fix serializing RTCRtpSendParameters ( Saúl Ibarra Corretgé 2024-08-14 11:11:08 +0200) ac7f578 android: remove no longer used replace rule from manifest (react-native-webrtc#1609) ( Saúl Ibarra Corretgé 2024-08-07 17:17:03 +0200) f6667c8 ios: fix exception in iOS 17+ w/ Xcode 15.4 ( mtdxc 2024-08-07 17:22:10 +0800) 4c34ae1 android: report actual size in camera MediaStreamTrack settings (react-native-webrtc#1598) ( davidliu 2024-08-07 17:56:57 +0900) fb02a5b pc: align createDataChannel with standard ( Saúl Ibarra Corretgé 2024-08-06 15:28:24 +0200) c0ddefd ci: remove flipper from gumtestapp (react-native-webrtc#1608) ( davidliu 2024-08-07 16:00:01 +0900) a1bb18a ios: add support for external cameras on iPad ( mtdxc 2024-07-10 20:25:23 +0800) * ios: Add RTCAudioSession helper methods needed for CallKit (react-native-webrtc#1614) * Fix package name references --------- Co-authored-by: mtdxc <mtdxc@126.com> Co-authored-by: Saúl Ibarra Corretgé <s@saghul.net> Co-authored-by: Saúl Ibarra Corretgé <saghul@jitsi.org>
1 parent 1121257 commit c10087e

19 files changed

+276
-44
lines changed

Documentation/iOSInstallation.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ See a sample app in the `examples/GumTestApp` directory.
88

99
**IMPORTANT:** Make sure you are using CocoaPods 1.10 or higher.
1010
You may have to change the `platform` field in your podfile.
11-
`react-native-webrtc` doesn't support iOS < 12
11+
`@livekit/react-native-webrtc` doesn't support iOS < 12
1212
Set it to '12.0' or above or you'll get an error when running `pod install`.
1313

1414
```
@@ -26,6 +26,33 @@ Navigate to `<ProjectFolder>/ios/<ProjectName>/` and edit `Info.plist`, add the
2626
<string>Microphone permission description</string>
2727
```
2828

29+
## CallKit
30+
31+
If your app uses a CallKit integration to handle incoming calls, then your
32+
CXProviderDelegate should call through to `RTCAudioSession.sharedInstance.audioSessionDidActivate/Deactivate` accordingly.
33+
34+
```
35+
#import <WebRTC/RTCAudioSession.h>
36+
37+
- (void) provider:(CXProvider *) provider didActivateAudioSession:(AVAudioSession *) audioSession {
38+
[[RTCAudioSession sharedInstance] audioSessionDidActivate:[AVAudioSession sharedInstance]];
39+
}
40+
41+
- (void) provider:(CXProvider *) provider didDeactivateAudioSession:(AVAudioSession *) audioSession {
42+
[[RTCAudioSession sharedInstance] audioSessionDidDeactivate:[AVAudioSession sharedInstance]];
43+
}
44+
```
45+
46+
Javascript methods are also provided to call these methods:
47+
48+
```
49+
import { RTCAudioSession } from '@livekit/react-native-webrtc'
50+
51+
// Call as needed.
52+
RTCAudioSession.audioSessionDidActivate();
53+
RTCAudioSession.audioSessionDidDeactivate();
54+
```
55+
2956
## Library not loaded/Code signature invalid
3057

3158
This is an issue with iOS 13.3.1.

Documentation/tvOSInstallation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Change the following dependency in your projects `package.json` file to get star
1313

1414
**IMPORTANT:** Make sure you are using CocoaPods 1.10 or higher.
1515
You may have to change the `platform` field in your podfile.
16-
`react-native-webrtc` doesn't support tvOS < 16. Set it to '16.0' or above.
16+
`@livekit/react-native-webrtc` doesn't support tvOS < 16. Set it to '16.0' or above.
1717
Older versions of tvOS don't support WebRTC.
1818

1919
```

android/src/main/AndroidManifest.xml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,4 @@
88
android:foregroundServiceType="mediaProjection">
99
</service>
1010
</application>
11-
<uses-feature
12-
android:name="android.hardware.usb.host"
13-
android:required="false"
14-
tools:node="replace"
15-
/>
1611
</manifest>

android/src/main/java/com/oney/WebRTCModule/AbstractVideoCaptureController.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
import org.webrtc.VideoCapturer;
44

55
public abstract class AbstractVideoCaptureController {
6-
protected int width;
7-
protected int height;
8-
private final int fps;
6+
protected final int targetWidth;
7+
protected final int targetHeight;
8+
protected final int targetFps;
9+
10+
protected int actualWidth;
11+
protected int actualHeight;
12+
protected int actualFps;
913

1014
/**
1115
* {@link VideoCapturer} which this controller manages.
@@ -15,9 +19,12 @@ public abstract class AbstractVideoCaptureController {
1519
protected CapturerEventsListener capturerEventsListener;
1620

1721
public AbstractVideoCaptureController(int width, int height, int fps) {
18-
this.width = width;
19-
this.height = height;
20-
this.fps = fps;
22+
this.targetWidth = width;
23+
this.targetHeight = height;
24+
this.targetFps = fps;
25+
this.actualWidth = width;
26+
this.actualHeight = height;
27+
this.actualFps = fps;
2128
}
2229

2330
public void initializeVideoCapturer() {
@@ -32,15 +39,15 @@ public void dispose() {
3239
}
3340

3441
public int getHeight() {
35-
return height;
42+
return actualHeight;
3643
}
3744

3845
public int getWidth() {
39-
return width;
46+
return actualWidth;
4047
}
4148

4249
public int getFrameRate() {
43-
return fps;
50+
return actualFps;
4451
}
4552

4653
public VideoCapturer getVideoCapturer() {
@@ -49,7 +56,7 @@ public VideoCapturer getVideoCapturer() {
4956

5057
public void startCapture() {
5158
try {
52-
videoCapturer.startCapture(width, height, fps);
59+
videoCapturer.startCapture(targetWidth, targetHeight, targetFps);
5360
} catch (RuntimeException e) {
5461
// XXX This can only fail if we initialize the capturer incorrectly,
5562
// which we don't. Thus, ignore any failures here since we trust

android/src/main/java/com/oney/WebRTCModule/CameraCaptureController.java

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
package com.oney.WebRTCModule;
22

3+
import android.content.Context;
4+
import android.hardware.camera2.CameraManager;
35
import android.util.Log;
6+
import android.util.Pair;
7+
import androidx.annotation.Nullable;
48

59
import com.facebook.react.bridge.ReadableMap;
610

11+
import org.webrtc.Camera1Capturer;
12+
import org.webrtc.Camera1Helper;
13+
import org.webrtc.Camera2Capturer;
14+
import org.webrtc.Camera2Helper;
715
import org.webrtc.CameraEnumerator;
816
import org.webrtc.CameraVideoCapturer;
17+
import org.webrtc.Size;
918
import org.webrtc.VideoCapturer;
1019

1120
import java.util.ArrayList;
@@ -19,6 +28,7 @@ public class CameraCaptureController extends AbstractVideoCaptureController {
1928

2029
private boolean isFrontFacing;
2130

31+
private final Context context;
2232
private final CameraEnumerator cameraEnumerator;
2333
private final ReadableMap constraints;
2434

@@ -30,9 +40,10 @@ public class CameraCaptureController extends AbstractVideoCaptureController {
3040
*/
3141
private final CameraEventsHandler cameraEventsHandler = new CameraEventsHandler();
3242

33-
public CameraCaptureController(CameraEnumerator cameraEnumerator, ReadableMap constraints) {
43+
public CameraCaptureController(Context context, CameraEnumerator cameraEnumerator, ReadableMap constraints) {
3444
super(constraints.getInt("width"), constraints.getInt("height"), constraints.getInt("frameRate"));
3545

46+
this.context = context;
3647
this.cameraEnumerator = cameraEnumerator;
3748
this.constraints = constraints;
3849
}
@@ -75,7 +86,30 @@ protected VideoCapturer createVideoCapturer() {
7586
String deviceId = ReactBridgeUtil.getMapStrValue(this.constraints, "deviceId");
7687
String facingMode = ReactBridgeUtil.getMapStrValue(this.constraints, "facingMode");
7788

78-
return createVideoCapturer(deviceId, facingMode);
89+
Pair<String, VideoCapturer> result = createVideoCapturer(deviceId, facingMode);
90+
if(result == null) {
91+
return null;
92+
}
93+
94+
String cameraName = result.first;
95+
VideoCapturer videoCapturer = result.second;
96+
97+
// Find actual capture format.
98+
Size actualSize = null;
99+
if (videoCapturer instanceof Camera1Capturer) {
100+
int cameraId = Camera1Helper.getCameraId(cameraName);
101+
actualSize = Camera1Helper.findClosestCaptureFormat(cameraId, targetWidth, targetHeight);
102+
} else if (videoCapturer instanceof Camera2Capturer) {
103+
CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
104+
actualSize = Camera2Helper.findClosestCaptureFormat(cameraManager, cameraName, targetWidth, targetHeight);
105+
}
106+
107+
if (actualSize != null) {
108+
actualWidth = actualSize.width;
109+
actualHeight = actualSize.height;
110+
}
111+
112+
return videoCapturer;
79113
}
80114

81115
/**
@@ -117,10 +151,11 @@ public void onCameraSwitchError(String s) {
117151
* @param facingMode the facing of the requested video source such as
118152
* {@code user} and {@code environment}. If {@code null}, "user" is
119153
* presumed.
120-
* @return a {@code VideoCapturer} satisfying the {@code facingMode} or
121-
* {@code deviceId} constraint
154+
* @return a pair containing the deviceId and {@code VideoCapturer} satisfying the {@code facingMode} or
155+
* {@code deviceId} constraint, or null.
122156
*/
123-
private VideoCapturer createVideoCapturer(String deviceId, String facingMode) {
157+
@Nullable
158+
private Pair<String, VideoCapturer> createVideoCapturer(String deviceId, String facingMode) {
124159
String[] deviceNames = cameraEnumerator.getDeviceNames();
125160
List<String> failedDevices = new ArrayList<>();
126161

@@ -139,7 +174,7 @@ private VideoCapturer createVideoCapturer(String deviceId, String facingMode) {
139174
if (videoCapturer != null) {
140175
Log.d(TAG, message + " succeeded");
141176
this.isFrontFacing = cameraEnumerator.isFrontFacing(cameraName);
142-
return videoCapturer;
177+
return new Pair(cameraName, videoCapturer);
143178
} else {
144179
// fallback to facingMode
145180
Log.d(TAG, message + " failed");
@@ -161,7 +196,7 @@ private VideoCapturer createVideoCapturer(String deviceId, String facingMode) {
161196
if (videoCapturer != null) {
162197
Log.d(TAG, message + " succeeded");
163198
this.isFrontFacing = cameraEnumerator.isFrontFacing(name);
164-
return videoCapturer;
199+
return new Pair(name, videoCapturer);
165200
} else {
166201
Log.d(TAG, message + " failed");
167202
failedDevices.add(name);
@@ -176,7 +211,7 @@ private VideoCapturer createVideoCapturer(String deviceId, String facingMode) {
176211
if (videoCapturer != null) {
177212
Log.d(TAG, message + " succeeded");
178213
this.isFrontFacing = cameraEnumerator.isFrontFacing(name);
179-
return videoCapturer;
214+
return new Pair(name, videoCapturer);
180215
} else {
181216
Log.d(TAG, message + " failed");
182217
failedDevices.add(name);

android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ void getUserMedia(final ReadableMap constraints, final Callback successCallback,
192192
Log.d(TAG, "getUserMedia(video): " + videoConstraintsMap);
193193

194194
CameraCaptureController cameraCaptureController =
195-
new CameraCaptureController(getCameraEnumerator(), videoConstraintsMap);
195+
new CameraCaptureController(reactContext.getCurrentActivity(), getCameraEnumerator(), videoConstraintsMap);
196196

197197
videoTrack = createVideoTrack(cameraCaptureController);
198198
}

android/src/main/java/com/oney/WebRTCModule/ScreenCaptureController.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ public void onOrientationChanged(int orientation) {
4141
DisplayMetrics displayMetrics = DisplayUtils.getDisplayMetrics((Activity) context);
4242
final int width = displayMetrics.widthPixels;
4343
final int height = displayMetrics.heightPixels;
44-
if (width != ScreenCaptureController.this.width || height != ScreenCaptureController.this.height) {
45-
ScreenCaptureController.this.width = width;
46-
ScreenCaptureController.this.height = height;
44+
if (width != ScreenCaptureController.this.actualWidth || height != ScreenCaptureController.this.actualHeight) {
45+
ScreenCaptureController.this.actualWidth = width;
46+
ScreenCaptureController.this.actualHeight = height;
4747

4848
// Pivot to the executor thread because videoCapturer.changeCaptureFormat runs in the main
4949
// thread and may deadlock.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2023-2024 LiveKit, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.webrtc;
18+
19+
import androidx.annotation.Nullable;
20+
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
24+
/**
25+
* A helper to access package-protected methods used in [Camera2Session]
26+
* <p>
27+
* Note: cameraId as used in the Camera1XXX classes refers to the index within the list of cameras.
28+
*
29+
* @suppress
30+
*/
31+
32+
public class Camera1Helper {
33+
34+
public static int getCameraId(String deviceName) {
35+
return Camera1Enumerator.getCameraIndex(deviceName);
36+
}
37+
38+
@Nullable
39+
public static List<CameraEnumerationAndroid.CaptureFormat> getSupportedFormats(int cameraId) {
40+
return Camera1Enumerator.getSupportedFormats(cameraId);
41+
}
42+
43+
public static Size findClosestCaptureFormat(int cameraId, int width, int height) {
44+
List<CameraEnumerationAndroid.CaptureFormat> formats = getSupportedFormats(cameraId);
45+
46+
List<Size> sizes = new ArrayList<>();
47+
if (formats != null) {
48+
for (CameraEnumerationAndroid.CaptureFormat format : formats) {
49+
sizes.add(new Size(format.width, format.height));
50+
}
51+
}
52+
53+
return CameraEnumerationAndroid.getClosestSupportedSize(sizes, width, height);
54+
}
55+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2023-2024 LiveKit, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.webrtc;
18+
19+
import android.hardware.camera2.CameraManager;
20+
21+
import androidx.annotation.Nullable;
22+
23+
import java.util.ArrayList;
24+
import java.util.List;
25+
26+
/**
27+
* A helper to access package-protected methods used in [Camera2Session]
28+
* <p>
29+
* Note: cameraId as used in the Camera2XXX classes refers to the id returned
30+
* by [CameraManager.getCameraIdList].
31+
*/
32+
public class Camera2Helper {
33+
34+
@Nullable
35+
public static List<CameraEnumerationAndroid.CaptureFormat> getSupportedFormats(CameraManager cameraManager, @Nullable String cameraId) {
36+
return Camera2Enumerator.getSupportedFormats(cameraManager, cameraId);
37+
}
38+
39+
public static Size findClosestCaptureFormat(CameraManager cameraManager, @Nullable String cameraId, int width, int height) {
40+
List<CameraEnumerationAndroid.CaptureFormat> formats = getSupportedFormats(cameraManager, cameraId);
41+
42+
List<Size> sizes = new ArrayList<>();
43+
if (formats != null) {
44+
for (CameraEnumerationAndroid.CaptureFormat format : formats) {
45+
sizes.add(new Size(format.width, format.height));
46+
}
47+
}
48+
49+
return CameraEnumerationAndroid.getClosestSupportedSize(sizes, width, height);
50+
}
51+
}

examples/GumTestApp_macOS/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
StatusBar,
1818
} from 'react-native';
1919
import { Colors } from 'react-native/Libraries/NewAppScreen';
20-
import { mediaDevices, RTCView } from 'react-native-webrtc';
20+
import { mediaDevices, RTCView } from '@livekit/react-native-webrtc';
2121

2222
const App: () => React$Node = () => {
2323
const [stream, setStream] = useState(null);

0 commit comments

Comments
 (0)