mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-23 04:28:35 +00:00
Improve handling of missing camera during calls.
This commit is contained in:
committed by
Cody Henthorne
parent
faf0b630c1
commit
340b94f849
@@ -39,11 +39,14 @@ public class Camera implements CameraControl, CameraVideoCapturer.CameraSwitchHa
|
||||
private static final String TAG = Log.tag(Camera.class);
|
||||
|
||||
@NonNull private final Context context;
|
||||
@Nullable private final CameraVideoCapturer capturer;
|
||||
@Nullable private CameraVideoCapturer capturer;
|
||||
@Nullable private CameraEventListener cameraEventListener;
|
||||
@NonNull private final EglBaseWrapper eglBase;
|
||||
private final int cameraCount;
|
||||
@NonNull private CameraState.Direction activeDirection;
|
||||
private CameraState.Direction oldActiveDirection;
|
||||
private CapturerObserver observer;
|
||||
|
||||
private boolean enabled;
|
||||
private boolean isInitialized;
|
||||
private int orientation;
|
||||
@@ -79,6 +82,7 @@ public class Camera implements CameraControl, CameraVideoCapturer.CameraSwitchHa
|
||||
@Override
|
||||
public void initCapturer(@NonNull CapturerObserver observer) {
|
||||
if (capturer != null) {
|
||||
this.observer = observer; // save in case we need to disposeAndFlipCamera
|
||||
eglBase.performWithValidEglBase(base -> {
|
||||
capturer.initialize(SurfaceTextureHelper.create("WebRTC-SurfaceTextureHelper", base.getEglBaseContext()),
|
||||
context,
|
||||
@@ -99,6 +103,7 @@ public class Camera implements CameraControl, CameraVideoCapturer.CameraSwitchHa
|
||||
if (capturer == null || cameraCount < 2) {
|
||||
throw new AssertionError("Tried to flip the camera, but we only have " + cameraCount + " of them.");
|
||||
}
|
||||
oldActiveDirection = activeDirection;
|
||||
activeDirection = PENDING;
|
||||
capturer.switchCamera(this);
|
||||
}
|
||||
@@ -146,6 +151,28 @@ public class Camera implements CameraControl, CameraVideoCapturer.CameraSwitchHa
|
||||
}
|
||||
}
|
||||
|
||||
public void disposeAndFlipCamera() {
|
||||
if (capturer != null) {
|
||||
capturer.dispose();
|
||||
boolean wasInitialized = isInitialized;
|
||||
isInitialized = false;
|
||||
CameraState.Direction candidateDirection = oldActiveDirection.switchDirection();
|
||||
CameraVideoCapturer captureCandidate = createVideoCapturer(getCameraEnumerator(context), candidateDirection);
|
||||
if (captureCandidate != null) {
|
||||
capturer = captureCandidate;
|
||||
activeDirection = candidateDirection;
|
||||
if (wasInitialized) {
|
||||
initCapturer(this.observer);
|
||||
}
|
||||
if (enabled) {
|
||||
setEnabled(true);
|
||||
}
|
||||
} else {
|
||||
activeDirection = NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getCount() {
|
||||
return cameraCount;
|
||||
}
|
||||
@@ -204,7 +231,9 @@ public class Camera implements CameraControl, CameraVideoCapturer.CameraSwitchHa
|
||||
@Override
|
||||
public void onCameraSwitchError(String errorMessage) {
|
||||
Log.e(TAG, "onCameraSwitchError: " + errorMessage);
|
||||
if (cameraEventListener != null) cameraEventListener.onCameraSwitchCompleted(new CameraState(getActiveDirection(), getCount()));
|
||||
if (cameraEventListener != null) {
|
||||
cameraEventListener.onCameraSwitchFailure(new CameraState(getActiveDirection(), getCount()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class FilteredCamera2Enumerator extends Camera2Enumerator {
|
||||
@@ -314,7 +343,7 @@ public class Camera implements CameraControl, CameraVideoCapturer.CameraSwitchHa
|
||||
public void onCapturerStarted(boolean success) {
|
||||
observer.onCapturerStarted(success);
|
||||
if (success && cameraEventListener != null) {
|
||||
cameraEventListener.onFullyInitialized();
|
||||
cameraEventListener.onFullyInitialized(getCameraState());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ import androidx.annotation.NonNull;
|
||||
* onCameraSwitchCompleted is triggered by {@link org.webrtc.CameraVideoCapturer.CameraSwitchHandler}
|
||||
*/
|
||||
public interface CameraEventListener {
|
||||
void onFullyInitialized();
|
||||
void onFullyInitialized(@NonNull CameraState newCameraState);
|
||||
void onCameraSwitchCompleted(@NonNull CameraState newCameraState);
|
||||
void onCameraSwitchFailure(@NonNull CameraState newCameraState);
|
||||
void onCameraStopped();
|
||||
}
|
||||
|
||||
@@ -80,4 +80,23 @@ public abstract class DeviceAwareActionProcessor extends WebRtcActionProcessor {
|
||||
.cameraState(newCameraState)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull WebRtcServiceState handleCameraSwitchFailure(@NonNull WebRtcServiceState currentState, @NonNull CameraState newCameraState) {
|
||||
Log.i(tag, "handleCameraSwitchFailure():");
|
||||
|
||||
BroadcastVideoSink localSink = currentState.getVideoState().getLocalSink();
|
||||
if (localSink != null) {
|
||||
localSink.setRotateToRightSide(false);
|
||||
}
|
||||
if (currentState.getVideoState().getCamera() != null) {
|
||||
// Retry by recreating with the opposite preferred camera
|
||||
currentState.getVideoState().getCamera().disposeAndFlipCamera();
|
||||
}
|
||||
|
||||
return currentState.builder()
|
||||
.changeLocalDeviceState()
|
||||
.cameraState(newCameraState)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,6 @@ import org.thoughtcrime.securesms.service.webrtc.state.WebRtcEphemeralState;
|
||||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
|
||||
import org.thoughtcrime.securesms.util.AppForegroundObserver;
|
||||
import org.thoughtcrime.securesms.util.RecipientAccessList;
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.rx.RxStore;
|
||||
@@ -988,8 +987,11 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFullyInitialized() {
|
||||
process((s, p) -> p.handleOrientationChanged(s, s.getLocalDeviceState().isLandscapeEnabled(), s.getLocalDeviceState().getDeviceOrientation().getDegrees()));
|
||||
public void onFullyInitialized(@NonNull final CameraState newCameraState) {
|
||||
process((s, p) -> {
|
||||
WebRtcServiceState s1 = p.handleSetCameraDirection(s, newCameraState);
|
||||
return p.handleOrientationChanged(s1, s.getLocalDeviceState().isLandscapeEnabled(), s.getLocalDeviceState().getDeviceOrientation().getDegrees());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -997,6 +999,11 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
|
||||
process((s, p) -> p.handleCameraSwitchCompleted(s, newCameraState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraSwitchFailure(@NonNull final CameraState newCameraState) {
|
||||
process((s, p) -> p.handleCameraSwitchFailure(s, newCameraState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraStopped() {
|
||||
Log.i(TAG, "Camera error. Muting video.");
|
||||
|
||||
@@ -569,6 +569,11 @@ public abstract class WebRtcActionProcessor {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
public @NonNull WebRtcServiceState handleCameraSwitchFailure(@NonNull WebRtcServiceState currentState, @NonNull CameraState newCameraState) {
|
||||
Log.i(tag, "handleCameraSwitchFailure not processed");
|
||||
return currentState;
|
||||
}
|
||||
|
||||
public @NonNull WebRtcServiceState handleNetworkChanged(@NonNull WebRtcServiceState currentState, boolean available) {
|
||||
Log.i(tag, "handleNetworkChanged not processed");
|
||||
return currentState;
|
||||
@@ -630,6 +635,18 @@ public abstract class WebRtcActionProcessor {
|
||||
.build();
|
||||
}
|
||||
|
||||
protected @NonNull WebRtcServiceState handleSetCameraDirection(@NonNull WebRtcServiceState currentState, CameraState state) {
|
||||
BroadcastVideoSink sink = currentState.getVideoState().getLocalSink();
|
||||
if (sink != null) {
|
||||
sink.setRotateToRightSide(state.getActiveDirection() == CameraState.Direction.BACK);
|
||||
}
|
||||
|
||||
return currentState.builder()
|
||||
.changeLocalDeviceState()
|
||||
.cameraState(state)
|
||||
.build();
|
||||
}
|
||||
|
||||
//endregion Local device
|
||||
|
||||
//region End call
|
||||
|
||||
Reference in New Issue
Block a user