Skip to content

Commit

Permalink
new deps added
Browse files Browse the repository at this point in the history
  • Loading branch information
robertoviola-systemelectronics committed Jun 21, 2024
1 parent 128a3b2 commit dc750a4
Show file tree
Hide file tree
Showing 7 changed files with 370 additions and 0 deletions.
17 changes: 17 additions & 0 deletions server/src/main/java/org/cagnulein/android_remote/Codec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.cagnulein.android_remote;

public interface Codec {

enum Type {
VIDEO,
AUDIO,
}

Type getType();

int getId();

String getName();

String getMimeType();
}
78 changes: 78 additions & 0 deletions server/src/main/java/org/cagnulein/android_remote/CodecUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.cagnulein.android_remote;

import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public final class CodecUtils {

public static final class DeviceEncoder {
private final Codec codec;
private final MediaCodecInfo info;

DeviceEncoder(Codec codec, MediaCodecInfo info) {
this.codec = codec;
this.info = info;
}

public Codec getCodec() {
return codec;
}

public MediaCodecInfo getInfo() {
return info;
}
}

private CodecUtils() {
// not instantiable
}

public static void setCodecOption(MediaFormat format, String key, Object value) {
if (value instanceof Integer) {
format.setInteger(key, (Integer) value);
} else if (value instanceof Long) {
format.setLong(key, (Long) value);
} else if (value instanceof Float) {
format.setFloat(key, (Float) value);
} else if (value instanceof String) {
format.setString(key, (String) value);
}
}

private static MediaCodecInfo[] getEncoders(MediaCodecList codecs, String mimeType) {
List<MediaCodecInfo> result = new ArrayList<>();
for (MediaCodecInfo codecInfo : codecs.getCodecInfos()) {
if (codecInfo.isEncoder() && Arrays.asList(codecInfo.getSupportedTypes()).contains(mimeType)) {
result.add(codecInfo);
}
}
return result.toArray(new MediaCodecInfo[result.size()]);
}

public static List<DeviceEncoder> listVideoEncoders() {
List<DeviceEncoder> encoders = new ArrayList<>();
MediaCodecList codecs = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
for (VideoCodec codec : VideoCodec.values()) {
for (MediaCodecInfo info : getEncoders(codecs, codec.getMimeType())) {
encoders.add(new DeviceEncoder(codec, info));
}
}
return encoders;
}

public static List<DeviceEncoder> listAudioEncoders() {
List<DeviceEncoder> encoders = new ArrayList<>();
MediaCodecList codecs = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
for (AudioCodec codec : AudioCodec.values()) {
for (MediaCodecInfo info : getEncoders(codecs, codec.getMimeType())) {
encoders.add(new DeviceEncoder(codec, info));
}
}
return encoders;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.cagnulein.android_remote;

public class ConfigurationException extends Exception {
public ConfigurationException(String message) {
super(message);
}
}
53 changes: 53 additions & 0 deletions server/src/main/java/org/cagnulein/android_remote/FakeContent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.cagnulein.android_remote;

import android.annotation.TargetApi;
import android.content.AttributionSource;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.Build;
import android.os.Process;

public final class FakeContext extends ContextWrapper {

public static final String PACKAGE_NAME = "com.android.shell";
public static final int ROOT_UID = 0; // Like android.os.Process.ROOT_UID, but before API 29

private static final FakeContext INSTANCE = new FakeContext();

public static FakeContext get() {
return INSTANCE;
}

private FakeContext() {
super(Workarounds.getSystemContext());
}

@Override
public String getPackageName() {
return PACKAGE_NAME;
}

@Override
public String getOpPackageName() {
return PACKAGE_NAME;
}

@TargetApi(Build.VERSION_CODES.S)
@Override
public AttributionSource getAttributionSource() {
AttributionSource.Builder builder = new AttributionSource.Builder(Process.SHELL_UID);
builder.setPackageName(PACKAGE_NAME);
return builder.build();
}

// @Override to be added on SDK upgrade for Android 14
@SuppressWarnings("unused")
public int getDeviceId() {
return 0;
}

@Override
public Context getApplicationContext() {
return this;
}
}
56 changes: 56 additions & 0 deletions server/src/main/java/org/cagnulein/android_remote/IO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.cagnulein.android_remote;

import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Scanner;

public final class IO {
private IO() {
// not instantiable
}

public static void writeFully(FileDescriptor fd, ByteBuffer from) throws IOException {
// ByteBuffer position is not updated as expected by Os.write() on old Android versions, so
// count the remaining bytes manually.
// See <https://github.com/Genymobile/scrcpy/issues/291>.
int remaining = from.remaining();
while (remaining > 0) {
try {
int w = Os.write(fd, from);
if (BuildConfig.DEBUG && w < 0) {
// w should not be negative, since an exception is thrown on error
throw new AssertionError("Os.write() returned a negative value (" + w + ")");
}
remaining -= w;
} catch (ErrnoException e) {
if (e.errno != OsConstants.EINTR) {
throw new IOException(e);
}
}
}
}

public static void writeFully(FileDescriptor fd, byte[] buffer, int offset, int len) throws IOException {
writeFully(fd, ByteBuffer.wrap(buffer, offset, len));
}

public static String toString(InputStream inputStream) {
StringBuilder builder = new StringBuilder();
Scanner scanner = new Scanner(inputStream);
while (scanner.hasNextLine()) {
builder.append(scanner.nextLine()).append('\n');
}
return builder.toString();
}

public static boolean isBrokenPipe(IOException e) {
Throwable cause = e.getCause();
return cause instanceof ErrnoException && ((ErrnoException) cause).errno == OsConstants.EPIPE;
}
}
151 changes: 151 additions & 0 deletions server/src/main/java/org/cagnulein/android_remote/LogUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package org.cagnulein.android_remote;

import org.cagnulein.android_remote.wrappers.DisplayManager;
import org.cagnulein.android_remote.wrappers.ServiceManager;

import android.graphics.Rect;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.MediaCodec;
import android.util.Range;

import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

public final class LogUtils {

private LogUtils() {
// not instantiable
}

public static String buildVideoEncoderListMessage() {
StringBuilder builder = new StringBuilder("List of video encoders:");
List<CodecUtils.DeviceEncoder> videoEncoders = CodecUtils.listVideoEncoders();
if (videoEncoders.isEmpty()) {
builder.append("\n (none)");
} else {
for (CodecUtils.DeviceEncoder encoder : videoEncoders) {
builder.append("\n --video-codec=").append(encoder.getCodec().getName());
builder.append(" --video-encoder='").append(encoder.getInfo().getName()).append("'");
}
}
return builder.toString();
}

public static String buildAudioEncoderListMessage() {
StringBuilder builder = new StringBuilder("List of audio encoders:");
List<CodecUtils.DeviceEncoder> audioEncoders = CodecUtils.listAudioEncoders();
if (audioEncoders.isEmpty()) {
builder.append("\n (none)");
} else {
for (CodecUtils.DeviceEncoder encoder : audioEncoders) {
builder.append("\n --audio-codec=").append(encoder.getCodec().getName());
builder.append(" --audio-encoder='").append(encoder.getInfo().getName()).append("'");
}
}
return builder.toString();
}

public static String buildDisplayListMessage() {
StringBuilder builder = new StringBuilder("List of displays:");
DisplayManager displayManager = ServiceManager.getDisplayManager();
int[] displayIds = displayManager.getDisplayIds();
if (displayIds == null || displayIds.length == 0) {
builder.append("\n (none)");
} else {
for (int id : displayIds) {
builder.append("\n --display-id=").append(id).append(" (");
DisplayInfo displayInfo = displayManager.getDisplayInfo(id);
if (displayInfo != null) {
Size size = displayInfo.getSize();
builder.append(size.getWidth()).append("x").append(size.getHeight());
} else {
builder.append("size unknown");
}
builder.append(")");
}
}
return builder.toString();
}

private static String getCameraFacingName(int facing) {
switch (facing) {
case CameraCharacteristics.LENS_FACING_FRONT:
return "front";
case CameraCharacteristics.LENS_FACING_BACK:
return "back";
case CameraCharacteristics.LENS_FACING_EXTERNAL:
return "external";
default:
return "unknown";
}
}

public static String buildCameraListMessage(boolean includeSizes) {
StringBuilder builder = new StringBuilder("List of cameras:");
CameraManager cameraManager = ServiceManager.getCameraManager();
try {
String[] cameraIds = cameraManager.getCameraIdList();
if (cameraIds == null || cameraIds.length == 0) {
builder.append("\n (none)");
} else {
for (String id : cameraIds) {
builder.append("\n --camera-id=").append(id);
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);

int facing = characteristics.get(CameraCharacteristics.LENS_FACING);
builder.append(" (").append(getCameraFacingName(facing)).append(", ");

Rect activeSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
builder.append(activeSize.width()).append("x").append(activeSize.height());

try {
// Capture frame rates for low-FPS mode are the same for every resolution
Range<Integer>[] lowFpsRanges = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
SortedSet<Integer> uniqueLowFps = getUniqueSet(lowFpsRanges);
builder.append(", fps=").append(uniqueLowFps);
} catch (Exception e) {
// Some devices may provide invalid ranges, causing an IllegalArgumentException "lower must be less than or equal to upper"
Ln.w("Could not get available frame rates for camera " + id, e);
}

builder.append(')');

if (includeSizes) {
StreamConfigurationMap configs = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

android.util.Size[] sizes = configs.getOutputSizes(MediaCodec.class);
for (android.util.Size size : sizes) {
builder.append("\n - ").append(size.getWidth()).append('x').append(size.getHeight());
}

android.util.Size[] highSpeedSizes = configs.getHighSpeedVideoSizes();
if (highSpeedSizes.length > 0) {
builder.append("\n High speed capture (--camera-high-speed):");
for (android.util.Size size : highSpeedSizes) {
Range<Integer>[] highFpsRanges = configs.getHighSpeedVideoFpsRanges();
SortedSet<Integer> uniqueHighFps = getUniqueSet(highFpsRanges);
builder.append("\n - ").append(size.getWidth()).append("x").append(size.getHeight());
builder.append(" (fps=").append(uniqueHighFps).append(')');
}
}
}
}
}
} catch (CameraAccessException e) {
builder.append("\n (access denied)");
}
return builder.toString();
}

private static SortedSet<Integer> getUniqueSet(Range<Integer>[] ranges) {
SortedSet<Integer> set = new TreeSet<>();
for (Range<Integer> range : ranges) {
set.add(range.getUpper());
}
return set;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public final class ServiceManager {
private DisplayManager displayManager;
private InputManager inputManager;
private PowerManager powerManager;
private static ActivityManager activityManager;

public ServiceManager() {
try {
Expand Down Expand Up @@ -60,4 +61,11 @@ public PowerManager getPowerManager() {
}
return powerManager;
}

public static ActivityManager getActivityManager() {
if (activityManager == null) {
activityManager = ActivityManager.create();
}
return activityManager;
}
}

0 comments on commit dc750a4

Please sign in to comment.