Skip to content

Commit

Permalink
Refactor callback to sync wrappers
Browse files Browse the repository at this point in the history
  • Loading branch information
yume-chan committed Aug 13, 2023
1 parent 0d228de commit b85c902
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 17 deletions.
88 changes: 71 additions & 17 deletions server/src/main/java/com/genymobile/scrcpy/CameraEncoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.MediaCodec;
Expand All @@ -19,7 +20,8 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CameraEncoder extends SurfaceEncoder {

Expand Down Expand Up @@ -49,48 +51,100 @@ public CameraEncoder(int maxSize, String cameraId, CameraPosition cameraPosition
@SuppressLint("MissingPermission")
private CameraDevice openCamera(String id)
throws CameraAccessException, InterruptedException {
Semaphore semaphore = new Semaphore(0);
final CameraDevice[] result = new CameraDevice[1];
Ln.v("Open Camera: " + id);

CompletableFuture<CameraDevice> future = new CompletableFuture<>();
Workarounds.getCameraManager().openCamera(id, new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
result[0] = camera;
semaphore.release();
Ln.v("Open Camera Success");
future.complete(camera);
}

@Override
public void onDisconnected(CameraDevice camera) {

}

@Override
public void onError(CameraDevice camera, int error) {

int cameraAccessExceptionErrorCode;
switch (error) {
case CameraDevice.StateCallback.ERROR_CAMERA_IN_USE:
cameraAccessExceptionErrorCode = CameraAccessException.CAMERA_IN_USE;
break;
case CameraDevice.StateCallback.ERROR_MAX_CAMERAS_IN_USE:
cameraAccessExceptionErrorCode = CameraAccessException.MAX_CAMERAS_IN_USE;
break;
case CameraDevice.StateCallback.ERROR_CAMERA_DISABLED:
cameraAccessExceptionErrorCode = CameraAccessException.CAMERA_DISABLED;
break;
case CameraDevice.StateCallback.ERROR_CAMERA_DEVICE:
case CameraDevice.StateCallback.ERROR_CAMERA_SERVICE:
default:
cameraAccessExceptionErrorCode = CameraAccessException.CAMERA_ERROR;
break;
}
future.completeExceptionally(new CameraAccessException(cameraAccessExceptionErrorCode));
}
}, cameraHandler);
semaphore.acquire();
return result[0];

try {
return future.get();
} catch (ExecutionException e) {
throw (CameraAccessException) e.getCause();
}
}

@SuppressWarnings("deprecation")
private CameraCaptureSession createCaptureSession(CameraDevice camera, Surface surface)
throws CameraAccessException, InterruptedException {
Semaphore semaphore = new Semaphore(0);
final CameraCaptureSession[] result = new CameraCaptureSession[1];
Ln.v("Create Capture Session");

CompletableFuture<CameraCaptureSession> future = new CompletableFuture<>();
camera.createCaptureSession(Collections.singletonList(surface), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
result[0] = session;
semaphore.release();
Ln.v("Create Capture Session Success");
future.complete(session);
}

@Override
public void onConfigureFailed(CameraCaptureSession session) {
future.completeExceptionally(new CameraAccessException(CameraAccessException.CAMERA_ERROR));
}
}, cameraHandler);

try {
return future.get();
} catch (ExecutionException e) {
throw (CameraAccessException) e.getCause();
}
}

private void setRepeatingRequest(CameraCaptureSession session, CaptureRequest request)
throws CameraAccessException, InterruptedException {
Ln.v("Set Repeating Request");

CompletableFuture<Void> future = new CompletableFuture<>();
session.setRepeatingRequest(request, new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
long timestamp, long frameNumber) {
future.complete(null);
}

@Override
public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
CaptureFailure failure) {
future.completeExceptionally(new CameraAccessException(CameraAccessException.CAMERA_ERROR));
}
}, cameraHandler);
semaphore.acquire();
return result[0];

try {
future.get();
} catch (ExecutionException e) {
throw (CameraAccessException) e.getCause();
}
}

@Override
Expand Down Expand Up @@ -174,7 +228,7 @@ private void setSurfaceInternal(Surface surface) throws CameraAccessException {
.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
requestBuilder.addTarget(surface);
CaptureRequest request = requestBuilder.build();
session.setRepeatingRequest(request, null, cameraHandler);
setRepeatingRequest(session, request);
} catch (CameraAccessException e) {
throw e;
} catch (Exception e) {
Expand Down Expand Up @@ -209,7 +263,7 @@ protected void setSurface(Surface surface) throws CaptureForegroundException {
try {
trySetSurface(5, 100, surface);
} finally {
Workarounds.stopForegroundWorkaround();
// Workarounds.stopForegroundWorkaround();
}
} else {
try {
Expand Down
3 changes: 3 additions & 0 deletions server/src/main/java/com/genymobile/scrcpy/Workarounds.java
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ public static CameraManager getCameraManager() {

public static synchronized void startForegroundWorkaround() {
if (foregroundWorkaroundCount++ == 0) {
Ln.v("Starting Foreground Workaround");

// Android 11 requires Apps to be at foreground to record audio.
// Normally, each App has its own user ID, so Android checks whether the
// requesting App has the user ID that's at the foreground.
Expand All @@ -368,6 +370,7 @@ public static synchronized void startForegroundWorkaround() {

public static synchronized void stopForegroundWorkaround() {
if (--foregroundWorkaroundCount == 0) {
Ln.v("Stopping Foreground Workaround");
ServiceManager.getActivityManager().forceStopPackage(FakeContext.PACKAGE_NAME);
}
}
Expand Down

0 comments on commit b85c902

Please sign in to comment.