That fuck shit the fascists are using
at master 332 lines 11 kB view raw
1package org.tm.archive.ringrtc; 2 3import android.content.Context; 4import android.hardware.camera2.CameraAccessException; 5import android.hardware.camera2.CameraCharacteristics; 6import android.hardware.camera2.CameraManager; 7import android.hardware.camera2.CameraMetadata; 8 9import androidx.annotation.NonNull; 10import androidx.annotation.Nullable; 11 12import com.annimon.stream.Stream; 13 14import org.signal.core.util.logging.Log; 15import org.signal.ringrtc.CameraControl; 16import org.tm.archive.components.webrtc.EglBaseWrapper; 17import org.webrtc.Camera1Enumerator; 18import org.webrtc.Camera2Capturer; 19import org.webrtc.Camera2Enumerator; 20import org.webrtc.CameraEnumerator; 21import org.webrtc.CameraVideoCapturer; 22import org.webrtc.CapturerObserver; 23import org.webrtc.SurfaceTextureHelper; 24import org.webrtc.VideoFrame; 25 26import java.util.LinkedList; 27import java.util.List; 28 29import static org.tm.archive.ringrtc.CameraState.Direction.BACK; 30import static org.tm.archive.ringrtc.CameraState.Direction.FRONT; 31import static org.tm.archive.ringrtc.CameraState.Direction.NONE; 32import static org.tm.archive.ringrtc.CameraState.Direction.PENDING; 33 34/** 35 * Encapsulate the camera functionality needed for video calling. 36 */ 37public class Camera implements CameraControl, CameraVideoCapturer.CameraSwitchHandler { 38 39 private static final String TAG = Log.tag(Camera.class); 40 41 @NonNull private final Context context; 42 @Nullable private final CameraVideoCapturer capturer; 43 @Nullable private CameraEventListener cameraEventListener; 44 @NonNull private final EglBaseWrapper eglBase; 45 private final int cameraCount; 46 @NonNull private CameraState.Direction activeDirection; 47 private boolean enabled; 48 private boolean isInitialized; 49 private int orientation; 50 51 public Camera(@NonNull Context context, 52 @NonNull CameraEventListener cameraEventListener, 53 @NonNull EglBaseWrapper eglBase, 54 @NonNull CameraState.Direction desiredCameraDirection) 55 { 56 this.context = context; 57 this.cameraEventListener = cameraEventListener; 58 this.eglBase = eglBase; 59 CameraEnumerator enumerator = getCameraEnumerator(context); 60 cameraCount = enumerator.getDeviceNames().length; 61 62 CameraState.Direction firstChoice = desiredCameraDirection.isUsable() ? desiredCameraDirection : FRONT; 63 64 CameraVideoCapturer capturerCandidate = createVideoCapturer(enumerator, firstChoice); 65 if (capturerCandidate != null) { 66 activeDirection = firstChoice; 67 } else { 68 CameraState.Direction secondChoice = firstChoice.switchDirection(); 69 capturerCandidate = createVideoCapturer(enumerator, secondChoice); 70 if (capturerCandidate != null) { 71 activeDirection = secondChoice; 72 } else { 73 activeDirection = NONE; 74 } 75 } 76 capturer = capturerCandidate; 77 } 78 79 @Override 80 public void initCapturer(@NonNull CapturerObserver observer) { 81 if (capturer != null) { 82 eglBase.performWithValidEglBase(base -> { 83 capturer.initialize(SurfaceTextureHelper.create("WebRTC-SurfaceTextureHelper", base.getEglBaseContext()), 84 context, 85 new CameraCapturerWrapper(observer)); 86 capturer.setOrientation(orientation); 87 isInitialized = true; 88 }); 89 } 90 } 91 92 @Override 93 public boolean hasCapturer() { 94 return capturer != null; 95 } 96 97 @Override 98 public void flip() { 99 if (capturer == null || cameraCount < 2) { 100 throw new AssertionError("Tried to flip the camera, but we only have " + cameraCount + " of them."); 101 } 102 activeDirection = PENDING; 103 capturer.switchCamera(this); 104 } 105 106 @Override 107 public void setOrientation(@Nullable Integer orientation) { 108 this.orientation = orientation; 109 110 if (isInitialized && capturer != null) { 111 capturer.setOrientation(orientation); 112 } 113 } 114 115 @Override 116 public void setEnabled(boolean enabled) { 117 Log.i(TAG, "setEnabled(): " + enabled); 118 119 this.enabled = enabled; 120 121 if (capturer == null) { 122 return; 123 } 124 125 try { 126 if (enabled) { 127 Log.i(TAG, "setEnabled(): starting capture"); 128 capturer.startCapture(1280, 720, 30); 129 } else { 130 Log.i(TAG, "setEnabled(): stopping capture"); 131 capturer.stopCapture(); 132 } 133 } catch (InterruptedException e) { 134 Log.w(TAG, "Got interrupted while trying to stop video capture", e); 135 } 136 } 137 138 public void setCameraEventListener(@Nullable CameraEventListener cameraEventListener) { 139 this.cameraEventListener = cameraEventListener; 140 } 141 142 public void dispose() { 143 if (capturer != null) { 144 capturer.dispose(); 145 isInitialized = false; 146 } 147 } 148 149 int getCount() { 150 return cameraCount; 151 } 152 153 @NonNull CameraState.Direction getActiveDirection() { 154 return enabled ? activeDirection : NONE; 155 } 156 157 @NonNull public CameraState getCameraState() { 158 return new CameraState(getActiveDirection(), getCount()); 159 } 160 161 @Nullable CameraVideoCapturer getCapturer() { 162 return capturer; 163 } 164 165 public boolean isInitialized() { 166 return isInitialized; 167 } 168 169 private @Nullable CameraVideoCapturer createVideoCapturer(@NonNull CameraEnumerator enumerator, 170 @NonNull CameraState.Direction direction) 171 { 172 String[] deviceNames = enumerator.getDeviceNames(); 173 for (String deviceName : deviceNames) { 174 if ((direction == FRONT && enumerator.isFrontFacing(deviceName)) || 175 (direction == BACK && enumerator.isBackFacing(deviceName))) 176 { 177 return enumerator.createCapturer(deviceName, null); 178 } 179 } 180 181 return null; 182 } 183 184 private @NonNull CameraEnumerator getCameraEnumerator(@NonNull Context context) { 185 boolean camera2EnumeratorIsSupported = false; 186 try { 187 camera2EnumeratorIsSupported = Camera2Enumerator.isSupported(context); 188 } catch (final Throwable throwable) { 189 Log.w(TAG, "Camera2Enumator.isSupport() threw.", throwable); 190 } 191 192 Log.i(TAG, "Camera2 enumerator supported: " + camera2EnumeratorIsSupported); 193 194 return camera2EnumeratorIsSupported ? new FilteredCamera2Enumerator(context) 195 : new Camera1Enumerator(true); 196 } 197 198 @Override 199 public void onCameraSwitchDone(boolean isFrontFacing) { 200 activeDirection = isFrontFacing ? FRONT : BACK; 201 if (cameraEventListener != null) cameraEventListener.onCameraSwitchCompleted(new CameraState(getActiveDirection(), getCount())); 202 } 203 204 @Override 205 public void onCameraSwitchError(String errorMessage) { 206 Log.e(TAG, "onCameraSwitchError: " + errorMessage); 207 if (cameraEventListener != null) cameraEventListener.onCameraSwitchCompleted(new CameraState(getActiveDirection(), getCount())); 208 } 209 210 private static class FilteredCamera2Enumerator extends Camera2Enumerator { 211 212 private static final String TAG = Log.tag(Camera2Enumerator.class); 213 214 @NonNull private final Context context; 215 @Nullable private final CameraManager cameraManager; 216 @Nullable private String[] deviceNames; 217 218 FilteredCamera2Enumerator(@NonNull Context context) { 219 super(context); 220 221 this.context = context; 222 this.cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); 223 this.deviceNames = null; 224 } 225 226 private static boolean isMonochrome(@NonNull String deviceName, @NonNull CameraManager cameraManager) { 227 try { 228 CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(deviceName); 229 int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 230 231 if (capabilities != null) { 232 for (int capability : capabilities) { 233 if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) { 234 return true; 235 } 236 } 237 } 238 } catch (CameraAccessException e) { 239 return false; 240 } 241 242 return false; 243 } 244 245 private static boolean isLensFacing(@NonNull String deviceName, @NonNull CameraManager cameraManager, @NonNull Integer facing) { 246 try { 247 CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(deviceName); 248 Integer lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING); 249 250 return facing.equals(lensFacing); 251 } catch (CameraAccessException e) { 252 return false; 253 } 254 } 255 256 @Override 257 public @NonNull String[] getDeviceNames() { 258 if (deviceNames != null) { 259 return deviceNames; 260 } 261 262 try { 263 List<String> cameraList = new LinkedList<>(); 264 265 if (cameraManager != null) { 266 List<String> devices = Stream.of(cameraManager.getCameraIdList()) 267 .filterNot(id -> isMonochrome(id, cameraManager)) 268 .toList(); 269 270 String frontCamera = Stream.of(devices) 271 .filter(id -> isLensFacing(id, cameraManager, CameraMetadata.LENS_FACING_FRONT)) 272 .findFirst() 273 .orElse(null); 274 275 if (frontCamera != null) { 276 cameraList.add(frontCamera); 277 } 278 279 String backCamera = Stream.of(devices) 280 .filter(id -> isLensFacing(id, cameraManager, CameraMetadata.LENS_FACING_BACK)) 281 .findFirst() 282 .orElse(null); 283 284 if (backCamera != null) { 285 cameraList.add(backCamera); 286 } 287 } 288 289 this.deviceNames = cameraList.toArray(new String[0]); 290 } catch (CameraAccessException e) { 291 Log.e(TAG, "Camera access exception: " + e); 292 this.deviceNames = new String[] {}; 293 } 294 295 return deviceNames; 296 } 297 298 @Override 299 public @NonNull CameraVideoCapturer createCapturer(@Nullable String deviceName, 300 @Nullable CameraVideoCapturer.CameraEventsHandler eventsHandler) 301 { 302 return new Camera2Capturer(context, deviceName, eventsHandler, new FilteredCamera2Enumerator(context)); 303 } 304 } 305 306 private class CameraCapturerWrapper implements CapturerObserver { 307 private final CapturerObserver observer; 308 309 public CameraCapturerWrapper(@NonNull CapturerObserver observer) { 310 this.observer = observer; 311 } 312 313 @Override 314 public void onCapturerStarted(boolean success) { 315 observer.onCapturerStarted(success); 316 if (success && cameraEventListener != null) { 317 cameraEventListener.onFullyInitialized(); 318 } 319 } 320 321 @Override 322 public void onCapturerStopped() { 323 observer.onCapturerStopped(); 324 if (cameraEventListener != null) cameraEventListener.onCameraStopped(); 325 } 326 327 @Override 328 public void onFrameCaptured(VideoFrame videoFrame) { 329 observer.onFrameCaptured(videoFrame); 330 } 331 } 332}