The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3287 lines
146KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. //==============================================================================
  14. // This byte-code is generated from:
  15. //
  16. // native/java/com/rmsl/juce/CameraCaptureSessionCaptureCallback.java
  17. // native/java/com/rmsl/juce/CameraCaptureSessionStateCallback.java
  18. // native/java/com/rmsl/juce/CameraDeviceStateCallback.java
  19. // native/java/com/rmsl/juce/JuceOrientationEventListener.java
  20. //
  21. // files with min sdk version 21
  22. // See juce_core/native/java/README.txt on how to generate this byte-code.
  23. static const uint8 CameraSupportByteCode[] =
  24. {31,139,8,8,187,110,161,94,0,3,67,97,109,101,114,97,83,117,112,112,111,114,116,66,121,116,101,67,111,100,101,46,100,101,120,0,
  25. 149,152,93,108,28,213,21,199,207,157,157,221,89,239,174,215,227,181,243,217,36,56,95,182,3,113,54,137,227,40,101,29,59,198,113,
  26. 192,102,133,169,215,182,34,3,45,147,221,73,188,176,222,89,102,215,139,171,86,37,68,84,208,151,42,80,90,168,4,136,170,20,181,15,
  27. 84,110,9,132,7,30,82,21,149,240,0,10,136,190,165,18,84,133,7,154,7,132,42,20,85,60,244,127,63,198,158,93,175,93,99,233,183,
  28. 255,51,115,206,61,247,222,115,239,140,103,38,103,47,68,14,246,246,209,213,103,22,174,255,247,133,96,249,25,246,233,195,151,255,
  29. 18,189,241,193,31,255,57,248,226,196,252,238,238,4,81,137,136,22,166,143,192,146,127,79,181,18,157,38,121,190,13,92,99,68,91,
  30. 160,219,52,162,32,244,174,0,81,55,247,67,117,232,34,126,110,198,136,14,194,249,86,152,232,10,248,2,36,154,136,14,131,62,112,12,
  31. 220,7,170,224,50,248,26,116,69,136,190,15,158,4,127,6,255,0,70,148,232,40,248,1,120,22,188,11,190,2,29,200,191,27,116,129,219,
  32. 120,95,160,15,164,192,9,112,39,24,7,167,193,131,32,7,242,192,1,85,240,99,240,24,120,18,252,22,188,7,110,128,182,102,162,65,48,7,
  33. 158,6,175,129,143,192,87,160,57,78,212,9,70,192,3,160,10,30,3,191,6,47,131,63,128,55,193,219,224,93,240,33,248,12,124,13,162,
  34. 45,68,123,193,16,200,128,7,64,9,252,4,252,28,60,7,126,3,46,131,43,224,125,112,29,124,6,254,13,254,3,190,1,97,147,168,21,236,2,
  35. 221,166,172,55,95,3,3,160,196,132,50,18,202,70,40,17,97,58,132,97,19,186,39,52,37,132,19,150,146,18,106,29,219,193,6,176,17,
  36. 116,42,109,85,107,190,73,217,139,72,188,89,217,111,25,114,221,185,125,5,246,119,148,125,21,246,86,101,127,236,179,175,251,98,
  37. 254,5,123,155,178,191,132,189,93,217,55,97,239,80,182,142,9,220,162,236,118,216,29,202,222,227,179,143,248,236,147,176,119,41,
  38. 123,18,246,78,101,223,239,59,159,131,189,91,217,5,216,123,148,189,0,123,175,178,159,240,217,23,125,246,11,190,156,191,247,229,
  39. 92,12,243,186,50,234,23,245,77,208,184,168,177,60,110,81,106,42,13,168,122,234,74,67,74,99,98,69,120,251,176,210,56,237,19,26,
  40. 163,91,133,54,211,109,66,155,104,191,208,8,245,8,141,210,1,161,27,105,80,104,59,157,16,186,129,134,132,182,210,29,106,92,195,66,
  41. 219,232,164,24,159,38,250,137,99,183,116,43,77,42,61,168,244,144,210,195,66,77,26,80,58,162,244,148,210,59,149,166,197,124,
  42. 101,222,22,204,172,87,233,17,161,6,245,169,227,163,66,55,137,60,92,239,18,186,153,70,213,241,152,168,151,172,144,137,138,29,83,
  43. 245,187,155,228,254,101,190,58,50,165,31,155,164,230,35,207,121,245,213,148,38,212,70,110,81,126,175,238,94,158,83,202,111,
  44. 42,127,172,110,125,92,229,15,34,51,247,247,154,242,250,42,153,60,126,6,151,208,253,237,12,189,199,224,231,215,222,113,83,230,
  45. 200,92,32,154,122,130,145,241,184,241,75,227,85,227,114,213,8,146,63,238,212,170,113,161,154,184,241,85,227,12,17,23,193,76,248,
  46. 88,79,155,242,90,207,184,136,171,32,238,17,227,167,236,87,213,80,88,68,201,245,228,227,126,208,203,247,52,226,126,129,184,139,
  47. 198,43,236,13,253,111,213,112,147,136,74,160,87,126,223,200,155,178,166,153,63,33,238,117,196,45,26,239,24,127,215,63,15,226,
  48. 198,83,141,68,68,172,142,190,121,77,202,166,172,87,201,100,162,38,154,240,105,98,45,126,164,124,153,14,141,74,39,18,164,29,90,
  49. 246,93,168,241,181,213,248,126,86,227,107,175,241,93,172,241,109,168,241,61,87,227,219,168,124,114,156,47,45,141,83,19,227,12,
  50. 248,198,249,234,82,187,0,218,109,175,201,249,90,141,111,135,240,5,145,147,223,111,47,249,125,147,183,212,180,123,187,166,93,
  51. 135,240,133,68,75,162,191,122,99,57,24,160,161,224,76,66,247,141,229,253,165,118,58,218,117,138,118,222,126,103,10,205,119,61,
  52. 48,181,219,229,185,160,82,67,249,12,159,47,33,242,115,13,146,252,127,225,217,222,181,33,143,155,136,137,76,203,199,225,154,248,
  53. 38,177,71,252,199,81,213,135,55,174,160,178,131,106,140,94,31,242,255,148,204,31,80,118,120,41,70,230,245,236,168,106,99,168,
  54. 92,92,67,253,249,98,190,50,64,221,195,214,156,237,90,195,86,169,50,239,218,25,187,92,206,59,69,117,52,108,21,10,103,172,236,195,
  55. 7,30,178,170,22,117,54,138,204,84,172,74,93,220,14,25,119,210,174,230,179,118,3,63,27,37,54,70,59,199,230,179,246,184,155,
  56. 183,139,136,64,162,145,42,172,116,190,92,177,139,182,43,3,183,164,173,98,206,117,242,185,100,214,41,226,124,37,57,204,117,161,
  57. 146,162,193,37,215,172,229,230,30,181,92,59,153,21,189,30,78,54,26,229,158,186,9,165,232,248,183,76,80,51,143,20,37,191,93,243,
  58. 20,245,253,191,6,178,92,245,253,116,173,175,89,138,246,173,21,40,134,114,202,202,23,32,235,9,157,176,31,153,183,203,40,115,247,
  59. 58,66,203,243,5,68,246,172,30,57,233,84,172,66,93,248,242,188,170,121,251,209,228,106,251,32,69,189,233,172,51,151,116,231,
  60. 202,133,228,67,216,48,13,171,187,98,113,15,173,163,81,93,161,247,53,108,210,96,15,167,104,127,93,232,90,27,57,69,108,154,180,
  61. 233,81,48,70,129,233,177,81,254,147,38,29,63,194,156,161,32,126,96,135,132,140,145,193,53,61,54,38,79,164,211,104,152,70,32,34,
  62. 244,105,238,15,78,11,47,14,224,99,51,20,146,85,166,173,217,6,115,28,202,86,242,85,155,246,52,242,121,69,115,230,74,5,187,98,231,
  63. 104,231,26,81,124,239,32,100,239,26,33,247,186,206,57,23,103,16,118,235,26,97,25,190,181,138,89,123,232,140,227,242,94,247,
  64. 175,35,118,121,140,187,214,138,174,88,34,99,195,74,12,23,28,62,178,221,13,125,78,241,108,254,220,242,44,119,172,25,148,163,45,
  65. 141,252,19,182,149,251,33,109,202,174,216,54,178,227,237,43,28,39,243,101,220,213,138,118,150,143,121,227,10,247,136,235,58,
  66. 110,131,124,227,37,108,171,28,25,89,121,39,164,205,57,225,243,237,191,225,89,171,120,14,33,65,91,164,48,206,202,235,158,162,103,
  67. 93,36,187,103,126,238,140,237,146,62,235,148,43,212,196,127,39,157,169,178,77,225,165,221,146,104,176,55,90,234,119,66,91,
  68. 163,117,223,188,234,42,111,93,99,77,205,21,43,24,94,90,175,214,149,171,19,171,89,139,184,83,172,41,164,129,235,79,76,27,57,84,
  69. 169,218,97,173,172,142,225,45,89,212,89,118,82,115,9,35,200,91,5,121,155,34,163,228,218,252,254,68,186,139,210,147,225,202,251,
  70. 34,133,92,233,143,148,213,108,70,145,176,44,55,2,181,148,103,157,249,66,238,14,84,70,53,174,204,230,203,212,84,201,207,161,173,
  71. 53,87,162,30,109,96,218,136,247,247,244,208,209,192,212,68,198,136,95,162,126,24,41,110,12,195,24,231,198,168,54,53,105,196,
  72. 127,71,227,129,169,201,126,126,98,90,159,154,56,13,235,35,218,207,6,120,115,234,101,83,70,124,134,190,43,101,80,202,136,148,187,
  73. 165,116,169,208,3,172,155,31,30,145,114,187,214,125,59,215,19,242,176,51,48,112,236,123,70,252,56,15,187,135,159,32,13,15,
  74. 207,26,211,244,243,231,245,197,8,187,128,167,188,6,68,217,181,8,99,55,193,203,81,198,174,130,47,193,243,49,98,161,160,166,181,
  75. 162,237,59,177,70,237,54,177,79,98,140,125,3,158,111,102,236,18,184,134,151,191,160,30,208,182,161,205,141,230,250,248,157,236,
  76. 169,56,99,175,128,43,224,58,30,225,52,166,107,123,31,63,175,223,140,115,127,23,123,182,69,190,215,120,207,117,158,122,223,88,
  77. 248,51,143,247,157,133,63,19,121,223,90,188,119,125,254,189,133,171,247,205,37,68,203,223,93,88,135,124,175,231,223,94,152,41,
  78. 223,221,249,59,188,214,33,243,243,239,49,1,21,195,223,105,248,203,52,111,43,222,167,76,57,14,254,189,231,127,249,28,121,55,40,18,
  79. 0,0,0,0};
  80. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  81. STATICMETHOD (valueOf, "valueOf", "(Ljava/lang/String;)Landroid/graphics/Bitmap$CompressFormat;")
  82. DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidBitmapCompressFormat, "android/graphics/Bitmap$CompressFormat", 21)
  83. #undef JNI_CLASS_MEMBERS
  84. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  85. METHOD (close, "close", "()V") \
  86. METHOD (createCaptureRequest, "createCaptureRequest", "(I)Landroid/hardware/camera2/CaptureRequest$Builder;") \
  87. METHOD (createCaptureSession, "createCaptureSession", "(Ljava/util/List;Landroid/hardware/camera2/CameraCaptureSession$StateCallback;Landroid/os/Handler;)V")
  88. DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidCameraDevice, "android/hardware/camera2/CameraDevice", 21)
  89. #undef JNI_CLASS_MEMBERS
  90. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  91. METHOD (close, "close", "()V") \
  92. METHOD (getPlanes, "getPlanes", "()[Landroid/media/Image$Plane;")
  93. DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidImage, "android/media/Image", 21)
  94. #undef JNI_CLASS_MEMBERS
  95. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  96. METHOD (getBuffer, "getBuffer", "()Ljava/nio/ByteBuffer;")
  97. DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidImagePlane, "android/media/Image$Plane", 21)
  98. #undef JNI_CLASS_MEMBERS
  99. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  100. METHOD (acquireLatestImage, "acquireLatestImage", "()Landroid/media/Image;") \
  101. METHOD (close, "close", "()V") \
  102. METHOD (getSurface, "getSurface", "()Landroid/view/Surface;") \
  103. METHOD (setOnImageAvailableListener, "setOnImageAvailableListener", "(Landroid/media/ImageReader$OnImageAvailableListener;Landroid/os/Handler;)V") \
  104. STATICMETHOD (newInstance, "newInstance", "(IIII)Landroid/media/ImageReader;")
  105. DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidImageReader, "android/media/ImageReader", 21)
  106. #undef JNI_CLASS_MEMBERS
  107. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  108. METHOD (constructor, "<init>", "()V") \
  109. METHOD (getSurface, "getSurface", "()Landroid/view/Surface;") \
  110. METHOD (prepare, "prepare", "()V") \
  111. METHOD (release, "release", "()V") \
  112. METHOD (setAudioEncoder, "setAudioEncoder", "(I)V") \
  113. METHOD (setAudioSource, "setAudioSource", "(I)V") \
  114. METHOD (setOnErrorListener, "setOnErrorListener", "(Landroid/media/MediaRecorder$OnErrorListener;)V") \
  115. METHOD (setOnInfoListener, "setOnInfoListener", "(Landroid/media/MediaRecorder$OnInfoListener;)V") \
  116. METHOD (setOrientationHint, "setOrientationHint", "(I)V") \
  117. METHOD (setOutputFile, "setOutputFile", "(Ljava/lang/String;)V") \
  118. METHOD (setOutputFormat, "setOutputFormat", "(I)V") \
  119. METHOD (setVideoEncoder, "setVideoEncoder", "(I)V") \
  120. METHOD (setVideoEncodingBitRate, "setVideoEncodingBitRate", "(I)V") \
  121. METHOD (setVideoFrameRate, "setVideoFrameRate", "(I)V") \
  122. METHOD (setVideoSize, "setVideoSize", "(II)V") \
  123. METHOD (setVideoSource, "setVideoSource", "(I)V") \
  124. METHOD (start, "start", "()V") \
  125. METHOD (stop, "stop", "()V")
  126. DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidMediaRecorder, "android/media/MediaRecorder", 21)
  127. #undef JNI_CLASS_MEMBERS
  128. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  129. METHOD (constructor, "<init>", "(Landroid/content/Context;)V") \
  130. METHOD (getSurfaceTexture, "getSurfaceTexture", "()Landroid/graphics/SurfaceTexture;") \
  131. METHOD (isAvailable, "isAvailable", "()Z") \
  132. METHOD (setSurfaceTextureListener, "setSurfaceTextureListener", "(Landroid/view/TextureView$SurfaceTextureListener;)V") \
  133. METHOD (setTransform, "setTransform", "(Landroid/graphics/Matrix;)V")
  134. DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidTextureView, "android/view/TextureView", 21)
  135. #undef JNI_CLASS_MEMBERS
  136. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  137. METHOD (constructor, "<init>", "(Landroid/graphics/SurfaceTexture;)V")
  138. DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidSurface, "android/view/Surface", 21)
  139. #undef JNI_CLASS_MEMBERS
  140. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  141. METHOD (setDefaultBufferSize, "setDefaultBufferSize", "(II)V")
  142. DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidSurfaceTexture, "android/graphics/SurfaceTexture", 21)
  143. #undef JNI_CLASS_MEMBERS
  144. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  145. METHOD (getOutputSizesForClass, "getOutputSizes", "(Ljava/lang/Class;)[Landroid/util/Size;") \
  146. METHOD (getOutputSizesForFormat, "getOutputSizes", "(I)[Landroid/util/Size;") \
  147. METHOD (isOutputSupportedFor, "isOutputSupportedFor", "(I)Z") \
  148. METHOD (isOutputSupportedForSurface, "isOutputSupportedFor", "(Landroid/view/Surface;)Z")
  149. DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidStreamConfigurationMap, "android/hardware/camera2/params/StreamConfigurationMap", 21)
  150. #undef JNI_CLASS_MEMBERS
  151. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  152. METHOD (constructor, "<init>", "()V") \
  153. METHOD (toByteArray, "toByteArray", "()[B") \
  154. METHOD (size, "size", "()I")
  155. DECLARE_JNI_CLASS_WITH_MIN_SDK (ByteArrayOutputStream, "java/io/ByteArrayOutputStream", 21)
  156. #undef JNI_CLASS_MEMBERS
  157. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  158. METHOD (abortCaptures, "abortCaptures", "()V") \
  159. METHOD (capture, "capture", "(Landroid/hardware/camera2/CaptureRequest;Landroid/hardware/camera2/CameraCaptureSession$CaptureCallback;Landroid/os/Handler;)I") \
  160. METHOD (close, "close", "()V") \
  161. METHOD (setRepeatingRequest, "setRepeatingRequest", "(Landroid/hardware/camera2/CaptureRequest;Landroid/hardware/camera2/CameraCaptureSession$CaptureCallback;Landroid/os/Handler;)I") \
  162. METHOD (stopRepeating, "stopRepeating", "()V")
  163. DECLARE_JNI_CLASS_WITH_MIN_SDK (CameraCaptureSession, "android/hardware/camera2/CameraCaptureSession", 21)
  164. #undef JNI_CLASS_MEMBERS
  165. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  166. METHOD (get, "get", "(Landroid/hardware/camera2/CameraCharacteristics$Key;)Ljava/lang/Object;") \
  167. METHOD (getKeys, "getKeys", "()Ljava/util/List;") \
  168. STATICFIELD (CONTROL_AF_AVAILABLE_MODES, "CONTROL_AF_AVAILABLE_MODES", "Landroid/hardware/camera2/CameraCharacteristics$Key;") \
  169. STATICFIELD (LENS_FACING, "LENS_FACING", "Landroid/hardware/camera2/CameraCharacteristics$Key;") \
  170. STATICFIELD (SCALER_STREAM_CONFIGURATION_MAP, "SCALER_STREAM_CONFIGURATION_MAP", "Landroid/hardware/camera2/CameraCharacteristics$Key;") \
  171. STATICFIELD (SENSOR_ORIENTATION, "SENSOR_ORIENTATION", "Landroid/hardware/camera2/CameraCharacteristics$Key;")
  172. DECLARE_JNI_CLASS_WITH_MIN_SDK (CameraCharacteristics, "android/hardware/camera2/CameraCharacteristics", 21)
  173. #undef JNI_CLASS_MEMBERS
  174. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  175. METHOD (getName, "getName", "()Ljava/lang/String;")
  176. DECLARE_JNI_CLASS_WITH_MIN_SDK (CameraCharacteristicsKey, "android/hardware/camera2/CameraCharacteristics$Key", 21)
  177. #undef JNI_CLASS_MEMBERS
  178. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  179. METHOD (getCameraCharacteristics, "getCameraCharacteristics", "(Ljava/lang/String;)Landroid/hardware/camera2/CameraCharacteristics;") \
  180. METHOD (getCameraIdList, "getCameraIdList", "()[Ljava/lang/String;") \
  181. METHOD (openCamera, "openCamera", "(Ljava/lang/String;Landroid/hardware/camera2/CameraDevice$StateCallback;Landroid/os/Handler;)V")
  182. DECLARE_JNI_CLASS_WITH_MIN_SDK (CameraManager, "android/hardware/camera2/CameraManager", 21)
  183. #undef JNI_CLASS_MEMBERS
  184. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  185. STATICFIELD (CONTROL_AE_PRECAPTURE_TRIGGER, "CONTROL_AE_PRECAPTURE_TRIGGER", "Landroid/hardware/camera2/CaptureRequest$Key;") \
  186. STATICFIELD (CONTROL_AF_MODE, "CONTROL_AF_MODE", "Landroid/hardware/camera2/CaptureRequest$Key;") \
  187. STATICFIELD (CONTROL_AF_TRIGGER, "CONTROL_AF_TRIGGER", "Landroid/hardware/camera2/CaptureRequest$Key;") \
  188. STATICFIELD (CONTROL_MODE, "CONTROL_MODE", "Landroid/hardware/camera2/CaptureRequest$Key;")
  189. DECLARE_JNI_CLASS_WITH_MIN_SDK (CaptureRequest, "android/hardware/camera2/CaptureRequest", 21)
  190. #undef JNI_CLASS_MEMBERS
  191. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  192. METHOD (addTarget, "addTarget", "(Landroid/view/Surface;)V") \
  193. METHOD (build, "build", "()Landroid/hardware/camera2/CaptureRequest;") \
  194. METHOD (set, "set", "(Landroid/hardware/camera2/CaptureRequest$Key;Ljava/lang/Object;)V")
  195. DECLARE_JNI_CLASS_WITH_MIN_SDK (CaptureRequestBuilder, "android/hardware/camera2/CaptureRequest$Builder", 21)
  196. #undef JNI_CLASS_MEMBERS
  197. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  198. METHOD (get, "get", "(Landroid/hardware/camera2/CaptureResult$Key;)Ljava/lang/Object;") \
  199. STATICFIELD (CONTROL_AE_STATE, "CONTROL_AE_STATE", "Landroid/hardware/camera2/CaptureResult$Key;") \
  200. STATICFIELD (CONTROL_AF_STATE, "CONTROL_AF_STATE", "Landroid/hardware/camera2/CaptureResult$Key;")
  201. DECLARE_JNI_CLASS_WITH_MIN_SDK (CaptureResult, "android/hardware/camera2/CaptureResult", 21)
  202. #undef JNI_CLASS_MEMBERS
  203. //==============================================================================
  204. class AndroidRunnable : public juce::AndroidInterfaceImplementer
  205. {
  206. public:
  207. struct Owner
  208. {
  209. virtual ~Owner() {}
  210. virtual void run() = 0;
  211. };
  212. AndroidRunnable (Owner& ownerToUse)
  213. : owner (ownerToUse)
  214. {}
  215. private:
  216. Owner& owner;
  217. jobject invoke (jobject proxy, jobject method, jobjectArray args) override
  218. {
  219. auto* env = getEnv();
  220. auto methodName = juce::juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName));
  221. if (methodName == "run")
  222. {
  223. owner.run();
  224. return nullptr;
  225. }
  226. // invoke base class
  227. return AndroidInterfaceImplementer::invoke (proxy, method, args);
  228. }
  229. };
  230. //==============================================================================
  231. class TextureViewSurfaceTextureListener : public AndroidInterfaceImplementer
  232. {
  233. public:
  234. struct Owner
  235. {
  236. virtual ~Owner() {}
  237. virtual void onSurfaceTextureAvailable (LocalRef<jobject>& surface, int width, int height) = 0;
  238. virtual bool onSurfaceTextureDestroyed (LocalRef<jobject>& surface) = 0;
  239. virtual void onSurfaceTextureSizeChanged (LocalRef<jobject>& surface, int width, int height) = 0;
  240. virtual void onSurfaceTextureUpdated (LocalRef<jobject>& surface) = 0;
  241. };
  242. TextureViewSurfaceTextureListener (Owner& ownerToUse)
  243. : owner (ownerToUse)
  244. {}
  245. jobject invoke (jobject proxy, jobject method, jobjectArray args) override
  246. {
  247. auto* env = getEnv();
  248. auto methodName = juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName));
  249. int numArgs = args != nullptr ? env->GetArrayLength (args) : 0;
  250. if (methodName == "onSurfaceTextureAvailable" && numArgs == 3)
  251. {
  252. auto surface = LocalRef<jobject> (env->GetObjectArrayElement (args, 0));
  253. auto width = LocalRef<jobject> (env->GetObjectArrayElement (args, 1));
  254. auto height = LocalRef<jobject> (env->GetObjectArrayElement (args, 2));
  255. auto widthInt = env->CallIntMethod (width, JavaInteger.intValue);
  256. auto heightInt = env->CallIntMethod (height, JavaInteger.intValue);
  257. owner.onSurfaceTextureAvailable (surface, widthInt, heightInt);
  258. return nullptr;
  259. }
  260. else if (methodName == "onSurfaceTextureDestroyed" && numArgs == 1)
  261. {
  262. auto surface = LocalRef<jobject> (env->GetObjectArrayElement (args, 0));
  263. auto result = owner.onSurfaceTextureDestroyed (surface);
  264. return env->CallStaticObjectMethod (JavaBoolean, JavaBoolean.valueOf, result);
  265. }
  266. else if (methodName == "onSurfaceTextureSizeChanged" && numArgs == 3)
  267. {
  268. auto surface = LocalRef<jobject> (env->GetObjectArrayElement (args, 0));
  269. auto width = LocalRef<jobject> (env->GetObjectArrayElement (args, 1));
  270. auto height = LocalRef<jobject> (env->GetObjectArrayElement (args, 2));
  271. auto widthInt = env->CallIntMethod (width, JavaInteger.intValue);
  272. auto heightInt = env->CallIntMethod (height, JavaInteger.intValue);
  273. owner.onSurfaceTextureSizeChanged (surface, widthInt, heightInt);
  274. return nullptr;
  275. }
  276. else if (methodName == "onSurfaceTextureUpdated" && numArgs == 1)
  277. {
  278. auto surface = LocalRef<jobject> (env->GetObjectArrayElement (args, 0));
  279. owner.onSurfaceTextureUpdated (surface);
  280. return nullptr;
  281. }
  282. return AndroidInterfaceImplementer::invoke (proxy, method, args);
  283. }
  284. private:
  285. Owner& owner;
  286. };
  287. //==============================================================================
  288. class ImageReaderOnImageAvailableListener : public AndroidInterfaceImplementer
  289. {
  290. public:
  291. struct Owner
  292. {
  293. virtual ~Owner() {}
  294. virtual void onImageAvailable (LocalRef<jobject>& imageReader) = 0;
  295. };
  296. ImageReaderOnImageAvailableListener (Owner& ownerToUse)
  297. : owner (ownerToUse)
  298. {}
  299. jobject invoke (jobject proxy, jobject method, jobjectArray args) override
  300. {
  301. auto* env = getEnv();
  302. auto methodName = juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName));
  303. int numArgs = args != nullptr ? env->GetArrayLength (args) : 0;
  304. if (methodName == "onImageAvailable" && numArgs == 1)
  305. {
  306. auto imageReader = LocalRef<jobject> (env->GetObjectArrayElement (args, 0));
  307. owner.onImageAvailable (imageReader);
  308. return nullptr;
  309. }
  310. return AndroidInterfaceImplementer::invoke (proxy, method, args);
  311. }
  312. private:
  313. Owner& owner;
  314. };
  315. //==============================================================================
  316. class MediaRecorderOnInfoListener : public AndroidInterfaceImplementer
  317. {
  318. public:
  319. struct Owner
  320. {
  321. virtual ~Owner() {}
  322. virtual void onInfo (LocalRef<jobject>& mediaRecorder, int what, int extra) = 0;
  323. };
  324. MediaRecorderOnInfoListener (Owner& ownerToUse)
  325. : owner (ownerToUse)
  326. {}
  327. jobject invoke (jobject proxy, jobject method, jobjectArray args) override
  328. {
  329. auto* env = getEnv();
  330. auto methodName = juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName));
  331. int numArgs = args != nullptr ? env->GetArrayLength (args) : 0;
  332. if (methodName == "onInfo" && numArgs == 3)
  333. {
  334. auto mediaRecorder = LocalRef<jobject> (env->GetObjectArrayElement (args, 0));
  335. auto what = LocalRef<jobject> (env->GetObjectArrayElement (args, 1));
  336. auto extra = LocalRef<jobject> (env->GetObjectArrayElement (args, 2));
  337. auto whatInt = (int) env->CallIntMethod (what, JavaInteger.intValue);
  338. auto extraInt = (int) env->CallIntMethod (extra, JavaInteger.intValue);
  339. owner.onInfo (mediaRecorder, whatInt, extraInt);
  340. return nullptr;
  341. }
  342. return AndroidInterfaceImplementer::invoke (proxy, method, args);
  343. }
  344. private:
  345. Owner& owner;
  346. };
  347. //==============================================================================
  348. class MediaRecorderOnErrorListener : public AndroidInterfaceImplementer
  349. {
  350. public:
  351. struct Owner
  352. {
  353. virtual ~Owner() {}
  354. virtual void onError (LocalRef<jobject>& mediaRecorder, int what, int extra) = 0;
  355. };
  356. MediaRecorderOnErrorListener (Owner& ownerToUse)
  357. : owner (ownerToUse)
  358. {}
  359. jobject invoke (jobject proxy, jobject method, jobjectArray args) override
  360. {
  361. auto* env = getEnv();
  362. auto methodName = juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName));
  363. int numArgs = args != nullptr ? env->GetArrayLength (args) : 0;
  364. if (methodName == "onError" && numArgs == 3)
  365. {
  366. auto mediaRecorder = LocalRef<jobject> (env->GetObjectArrayElement (args, 0));
  367. auto what = LocalRef<jobject> (env->GetObjectArrayElement (args, 1));
  368. auto extra = LocalRef<jobject> (env->GetObjectArrayElement (args, 2));
  369. auto whatInt = (int) env->CallIntMethod (what, JavaInteger.intValue);
  370. auto extraInt = (int) env->CallIntMethod (extra, JavaInteger.intValue);
  371. owner.onError (mediaRecorder, whatInt, extraInt);
  372. return nullptr;
  373. }
  374. return AndroidInterfaceImplementer::invoke (proxy, method, args);
  375. }
  376. private:
  377. Owner& owner;
  378. };
  379. //==============================================================================
  380. struct CameraDevice::Pimpl
  381. : private ActivityLifecycleCallbacks
  382. {
  383. using InternalOpenCameraResultCallback = std::function<void(const String& /*cameraId*/, const String& /*error*/)>;
  384. Pimpl (CameraDevice& ownerToUse, const String& cameraIdToUse, int /*index*/,
  385. int minWidthToUse, int minHeightToUse, int maxWidthToUse, int maxHeightToUse,
  386. bool /*useHighQuality*/)
  387. : owner (ownerToUse),
  388. minWidth (minWidthToUse),
  389. minHeight (minHeightToUse),
  390. maxWidth (maxWidthToUse),
  391. maxHeight (maxHeightToUse),
  392. cameraId (cameraIdToUse),
  393. activityLifeListener (CreateJavaInterface (this, "android/app/Application$ActivityLifecycleCallbacks")),
  394. cameraManager (initialiseCameraManager()),
  395. cameraCharacteristics (initialiseCameraCharacteristics (cameraManager, cameraId)),
  396. streamConfigurationMap (cameraCharacteristics),
  397. previewDisplay (streamConfigurationMap.getPreviewBufferSize()),
  398. deviceOrientationChangeListener (previewDisplay)
  399. {
  400. startBackgroundThread();
  401. }
  402. ~Pimpl() override
  403. {
  404. auto* env = getEnv();
  405. env->CallVoidMethod (getAppContext().get(), AndroidApplication.unregisterActivityLifecycleCallbacks, activityLifeListener.get());
  406. activityLifeListener.clear();
  407. }
  408. JUCE_DECLARE_WEAK_REFERENCEABLE (Pimpl)
  409. String getCameraId() const noexcept { return cameraId; }
  410. void open (InternalOpenCameraResultCallback cameraOpenCallbackToUse)
  411. {
  412. cameraOpenCallback = std::move (cameraOpenCallbackToUse);
  413. // A valid camera open callback must be passed.
  414. jassert (cameraOpenCallback != nullptr);
  415. // The same camera can be opened only once!
  416. jassert (scopedCameraDevice == nullptr);
  417. if (cameraOpenCallback == nullptr || scopedCameraDevice != nullptr)
  418. return;
  419. WeakReference<Pimpl> safeThis (this);
  420. RuntimePermissions::request (RuntimePermissions::camera, [safeThis] (bool granted) mutable
  421. {
  422. if (safeThis != nullptr)
  423. safeThis->continueOpenRequest (granted);
  424. });
  425. }
  426. void continueOpenRequest (bool granted)
  427. {
  428. if (getAndroidSDKVersion() >= 21)
  429. {
  430. if (granted)
  431. {
  432. getEnv()->CallVoidMethod (getAppContext().get(), AndroidApplication.registerActivityLifecycleCallbacks, activityLifeListener.get());
  433. scopedCameraDevice.reset (new ScopedCameraDevice (*this, cameraId, cameraManager, handler, getAutoFocusModeToUse()));
  434. }
  435. else
  436. {
  437. invokeCameraOpenCallback ("Camera permission not granted");
  438. }
  439. }
  440. else
  441. {
  442. invokeCameraOpenCallback ("Camera requires android sdk version 21 or greater");
  443. }
  444. }
  445. bool openedOk() const noexcept { return scopedCameraDevice->openedOk(); }
  446. void takeStillPicture (std::function<void(const Image&)> pictureTakenCallbackToUse)
  447. {
  448. if (pictureTakenCallbackToUse == nullptr || currentCaptureSessionMode == nullptr)
  449. {
  450. jassertfalse;
  451. return;
  452. }
  453. if (currentCaptureSessionMode->isVideoRecordSession())
  454. {
  455. // Taking still pictures while recording video is not supported on Android.
  456. jassertfalse;
  457. return;
  458. }
  459. pictureTakenCallback = std::move (pictureTakenCallbackToUse);
  460. triggerStillPictureCapture();
  461. }
  462. void startRecordingToFile (const File& file, int /*quality*/)
  463. {
  464. if (! openedOk())
  465. {
  466. jassertfalse;
  467. return;
  468. }
  469. if (! previewDisplay.isReady())
  470. {
  471. // Did you remember to create and show a preview display?
  472. jassertfalse;
  473. return;
  474. }
  475. file.deleteFile();
  476. file.create();
  477. jassert (file.existsAsFile());
  478. // MediaRecorder can't handle videos larger than 1080p
  479. auto videoSize = chooseBestSize (minWidth, minHeight, jmin (maxWidth, 1080), maxHeight,
  480. streamConfigurationMap.getSupportedVideoRecordingOutputSizes());
  481. mediaRecorder.reset (new MediaRecorder (file.getFullPathName(), videoSize.getWidth(), videoSize.getHeight(),
  482. getCameraSensorOrientation(), getCameraLensFacing()));
  483. firstRecordedFrameTimeMs = Time::getCurrentTime();
  484. currentCaptureSessionMode.reset();
  485. startVideoRecordingMode (*mediaRecorder);
  486. }
  487. void stopRecording()
  488. {
  489. currentCaptureSessionMode.reset();
  490. mediaRecorder.reset();
  491. startPreviewMode (*imageReader);
  492. }
  493. Time getTimeOfFirstRecordedFrame() const
  494. {
  495. return firstRecordedFrameTimeMs;
  496. }
  497. static StringArray getAvailableDevices()
  498. {
  499. if (getAndroidSDKVersion() < 21)
  500. return StringArray(); // Camera requires SDK version 21 or later
  501. StringArray results;
  502. auto* env = getEnv();
  503. auto cameraManagerToUse = initialiseCameraManager();
  504. auto cameraIdArray = LocalRef<jobjectArray> ((jobjectArray) env->CallObjectMethod (cameraManagerToUse,
  505. CameraManager.getCameraIdList));
  506. results = javaStringArrayToJuce (cameraIdArray);
  507. for (auto& result : results)
  508. printDebugCameraInfo (cameraManagerToUse, result);
  509. return results;
  510. }
  511. void addListener (CameraDevice::Listener* listenerToAdd)
  512. {
  513. const ScopedLock sl (listenerLock);
  514. listeners.add (listenerToAdd);
  515. if (listeners.size() == 1)
  516. triggerStillPictureCapture();
  517. }
  518. void removeListener (CameraDevice::Listener* listenerToRemove)
  519. {
  520. const ScopedLock sl (listenerLock);
  521. listeners.remove (listenerToRemove);
  522. }
  523. private:
  524. enum
  525. {
  526. ERROR_CAMERA_IN_USE = 1,
  527. ERROR_MAX_CAMERAS_IN_USE = 2,
  528. ERROR_CAMERA_DISABLED = 3,
  529. ERROR_CAMERA_DEVICE = 4,
  530. ERROR_CAMERA_SERVICE = 5
  531. };
  532. static String cameraErrorCodeToString (int errorCode)
  533. {
  534. switch (errorCode)
  535. {
  536. case ERROR_CAMERA_IN_USE: return "Camera already in use.";
  537. case ERROR_MAX_CAMERAS_IN_USE: return "Too many opened camera devices.";
  538. case ERROR_CAMERA_DISABLED: return "Camera disabled.";
  539. case ERROR_CAMERA_DEVICE: return "Fatal error.";
  540. case ERROR_CAMERA_SERVICE: return "Fatal error. Reboot required or persistent hardware problem.";
  541. default: return "Unknown error.";
  542. }
  543. }
  544. static LocalRef<jobject> initialiseCameraManager()
  545. {
  546. return LocalRef<jobject> (getEnv()->CallObjectMethod (getAppContext().get(), AndroidContext.getSystemService,
  547. javaString ("camera").get()));
  548. }
  549. static LocalRef<jobject> initialiseCameraCharacteristics (const GlobalRef& cameraManager, const String& cameraId)
  550. {
  551. return LocalRef<jobject> (getEnv()->CallObjectMethod (cameraManager,
  552. CameraManager.getCameraCharacteristics,
  553. javaString (cameraId).get()));
  554. }
  555. static void printDebugCameraInfo (const LocalRef<jobject>& cameraManagerToUse, const String& cameraId)
  556. {
  557. auto* env = getEnv();
  558. auto characteristics = LocalRef<jobject> (env->CallObjectMethod (cameraManagerToUse,
  559. CameraManager.getCameraCharacteristics,
  560. javaString (cameraId).get()));
  561. auto keysList = LocalRef<jobject> (env->CallObjectMethod (characteristics, CameraCharacteristics.getKeys));
  562. const int size = env->CallIntMethod (keysList, JavaList.size);
  563. JUCE_CAMERA_LOG ("Camera id: " + cameraId + ", characteristics keys num: " + String (size));
  564. for (int i = 0; i < size; ++i)
  565. {
  566. auto key = LocalRef<jobject> (env->CallObjectMethod (keysList, JavaList.get, i));
  567. auto jKeyName = LocalRef<jstring> ((jstring) env->CallObjectMethod (key, CameraCharacteristicsKey.getName));
  568. auto keyName = juceString (jKeyName);
  569. auto keyValue = LocalRef<jobject> (env->CallObjectMethod (characteristics, CameraCharacteristics.get, key.get()));
  570. auto jKeyValueString = LocalRef<jstring> ((jstring) env->CallObjectMethod (keyValue, JavaObject.toString));
  571. auto keyValueString = juceString (jKeyValueString);
  572. auto &kvs = keyValueString;
  573. if (kvs.startsWith ("[I") || kvs.startsWith ("[F") || kvs.startsWith ("[Z") || kvs.startsWith ("[B"))
  574. {
  575. printPrimitiveArrayElements (keyValue, keyName, keyValueString);
  576. }
  577. else if (kvs.startsWith ("[Landroid.util.Range"))
  578. {
  579. printRangeArrayElements (keyValue, keyName);
  580. }
  581. else
  582. {
  583. int chunkSize = 256;
  584. if (keyValueString.length() > chunkSize)
  585. {
  586. JUCE_CAMERA_LOG ("Key: " + keyName);
  587. for (int j = 0, k = 1; j < keyValueString.length(); j += chunkSize, ++k)
  588. JUCE_CAMERA_LOG ("value part " + String (k) + ": " + keyValueString.substring (j, k + chunkSize));
  589. }
  590. else
  591. {
  592. JUCE_CAMERA_LOG ("Key: " + keyName + ", value: " + keyValueString);
  593. }
  594. }
  595. ignoreUnused (keyName);
  596. }
  597. }
  598. static void printPrimitiveArrayElements (const LocalRef<jobject>& keyValue, const String& keyName,
  599. const String& keyValueString)
  600. {
  601. ignoreUnused (keyName);
  602. String result = "[";
  603. auto* env = getEnv();
  604. #define PRINT_ELEMENTS(elem_type, array_type, fun_name_middle) \
  605. { \
  606. elem_type* elements = env->Get##fun_name_middle##ArrayElements ((array_type) keyValue.get(), nullptr); \
  607. int size = env->GetArrayLength ((array_type) keyValue.get()); \
  608. \
  609. for (int i = 0; i < size - 1; ++i) \
  610. result << String (elements[i]) << " "; \
  611. \
  612. if (size > 0) \
  613. result << String (elements[size - 1]); \
  614. \
  615. env->Release##fun_name_middle##ArrayElements ((array_type) keyValue.get(), elements, 0); \
  616. }
  617. if (keyValueString.startsWith ("[I"))
  618. PRINT_ELEMENTS (jint, jintArray, Int)
  619. else if (keyValueString.startsWith ("[F"))
  620. PRINT_ELEMENTS (float, jfloatArray, Float)
  621. else if (keyValueString.startsWith ("[Z"))
  622. PRINT_ELEMENTS (jboolean, jbooleanArray, Boolean)
  623. else if (keyValueString.startsWith ("[B"))
  624. PRINT_ELEMENTS (jbyte, jbyteArray, Byte);
  625. #undef PRINT_ELEMENTS
  626. result << "]";
  627. JUCE_CAMERA_LOG ("Key: " + keyName + ", value: " + result);
  628. }
  629. static void printRangeArrayElements (const LocalRef<jobject>& rangeArray, const String& keyName)
  630. {
  631. auto* env = getEnv();
  632. jobjectArray ranges = static_cast<jobjectArray> (rangeArray.get());
  633. int numRanges = env->GetArrayLength (ranges);
  634. String result;
  635. for (int i = 0; i < numRanges; ++i)
  636. {
  637. auto range = LocalRef<jobject> (env->GetObjectArrayElement (ranges, i));
  638. auto jRangeString = LocalRef<jstring> ((jstring) env->CallObjectMethod (range, AndroidRange.toString));
  639. result << juceString (jRangeString) << " ";
  640. }
  641. ignoreUnused (keyName);
  642. JUCE_CAMERA_LOG ("Key: " + keyName + ", value: " + result);
  643. }
  644. //==============================================================================
  645. class StreamConfigurationMap
  646. {
  647. public:
  648. StreamConfigurationMap (const GlobalRef& cameraCharacteristicsToUse)
  649. : scalerStreamConfigurationMap (getStreamConfigurationMap (cameraCharacteristicsToUse)),
  650. supportedPreviewOutputSizes (retrieveOutputSizes (scalerStreamConfigurationMap,
  651. getClassForName ("android.graphics.SurfaceTexture"),
  652. -1)),
  653. supportedStillImageOutputSizes (retrieveOutputSizes (scalerStreamConfigurationMap,
  654. LocalRef<jobject>(),
  655. jpegImageFormat)),
  656. supportedVideoRecordingOutputSizes (retrieveOutputSizes (scalerStreamConfigurationMap,
  657. getClassForName ("android.media.MediaRecorder"),
  658. -1)),
  659. defaultPreviewSize (getSmallestSize (supportedPreviewOutputSizes)),
  660. previewBufferSize (getLargestSize (supportedPreviewOutputSizes))
  661. {
  662. printSizesLog (supportedPreviewOutputSizes, "SurfaceTexture");
  663. printSizesLog (supportedStillImageOutputSizes, "JPEG");
  664. printSizesLog (supportedVideoRecordingOutputSizes, "MediaRecorder");
  665. }
  666. Array<Rectangle<int>> getSupportedPreviewOutputSizes() const noexcept { return supportedPreviewOutputSizes; }
  667. Array<Rectangle<int>> getSupportedStillImageOutputSizes() const noexcept { return supportedStillImageOutputSizes; }
  668. Array<Rectangle<int>> getSupportedVideoRecordingOutputSizes() const noexcept { return supportedVideoRecordingOutputSizes; }
  669. Rectangle<int> getDefaultPreviewSize() const noexcept { return defaultPreviewSize; }
  670. Rectangle<int> getPreviewBufferSize() const noexcept { return previewBufferSize; }
  671. bool isOutputSupportedForSurface (const LocalRef<jobject>& surface) const
  672. {
  673. return getEnv()->CallBooleanMethod (scalerStreamConfigurationMap, AndroidStreamConfigurationMap.isOutputSupportedForSurface, surface.get()) != 0;
  674. }
  675. static constexpr int jpegImageFormat = 256;
  676. private:
  677. GlobalRef scalerStreamConfigurationMap;
  678. Array<Rectangle<int>> supportedPreviewOutputSizes;
  679. Array<Rectangle<int>> supportedStillImageOutputSizes;
  680. Array<Rectangle<int>> supportedVideoRecordingOutputSizes;
  681. Rectangle<int> defaultPreviewSize, previewBufferSize;
  682. GlobalRef getStreamConfigurationMap (const GlobalRef& cameraCharacteristicsToUse)
  683. {
  684. auto* env = getEnv();
  685. auto scalerStreamConfigurationMapKey = LocalRef<jobject> (env->GetStaticObjectField (CameraCharacteristics,
  686. CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP));
  687. return GlobalRef (LocalRef<jobject> (env->CallObjectMethod (cameraCharacteristicsToUse,
  688. CameraCharacteristics.get,
  689. scalerStreamConfigurationMapKey.get())));
  690. }
  691. static Array<Rectangle<int>> retrieveOutputSizes (GlobalRef& scalerStreamConfigurationMap,
  692. const LocalRef<jobject>& outputClass,
  693. int format)
  694. {
  695. Array<Rectangle<int>> result;
  696. auto* env = getEnv();
  697. auto outputSizes = outputClass.get() != nullptr
  698. ? LocalRef<jobjectArray> ((jobjectArray) env->CallObjectMethod (scalerStreamConfigurationMap,
  699. AndroidStreamConfigurationMap.getOutputSizesForClass,
  700. outputClass.get()))
  701. : LocalRef<jobjectArray> ((jobjectArray) env->CallObjectMethod (scalerStreamConfigurationMap,
  702. AndroidStreamConfigurationMap.getOutputSizesForFormat,
  703. (jint) format));
  704. if (format != -1)
  705. {
  706. auto supported = (env->CallBooleanMethod (scalerStreamConfigurationMap, AndroidStreamConfigurationMap.isOutputSupportedFor, (jint) format) != 0);
  707. if (! supported)
  708. {
  709. // The output format is not supported by this device, still image capture will not work!
  710. jassertfalse;
  711. return {};
  712. }
  713. }
  714. int numSizes = env->GetArrayLength (outputSizes);
  715. jassert (numSizes > 0);
  716. for (int i = 0; i < numSizes; ++i)
  717. {
  718. auto size = LocalRef<jobject> (env->GetObjectArrayElement (outputSizes, i));
  719. auto width = env->CallIntMethod (size, AndroidSize.getWidth);
  720. auto height = env->CallIntMethod (size, AndroidSize.getHeight);
  721. result.add (Rectangle<int> (0, 0, width, height));
  722. }
  723. return result;
  724. }
  725. static LocalRef<jobject> getClassForName (const String& name)
  726. {
  727. return LocalRef<jobject> (getEnv()->CallStaticObjectMethod (JavaClass, JavaClass.forName,
  728. javaString (name).get()));
  729. }
  730. static void printSizesLog (const Array<Rectangle<int>>& sizes, const String& className)
  731. {
  732. ignoreUnused (sizes, className);
  733. JUCE_CAMERA_LOG ("Sizes for class " + className);
  734. #if JUCE_CAMERA_LOG_ENABLED
  735. for (auto& s : sizes)
  736. JUCE_CAMERA_LOG (s.toString() + "\n");
  737. #endif
  738. }
  739. Rectangle<int> getSmallestSize (const Array<Rectangle<int>>& sizes) const
  740. {
  741. if (sizes.size() == 0)
  742. return {};
  743. auto smallestSize = sizes[0];
  744. for (auto& size : sizes)
  745. {
  746. if (size.getWidth() < smallestSize.getWidth() && size.getHeight() < smallestSize.getHeight())
  747. smallestSize = size;
  748. }
  749. return smallestSize;
  750. }
  751. Rectangle<int> getLargestSize (const Array<Rectangle<int>>& sizes) const
  752. {
  753. if (sizes.size() == 0)
  754. return {};
  755. auto largestSize = sizes[0];
  756. for (auto& size : sizes)
  757. {
  758. if (size.getWidth() > largestSize.getWidth() && size.getHeight() > largestSize.getHeight())
  759. largestSize = size;
  760. }
  761. return largestSize;
  762. }
  763. };
  764. //==============================================================================
  765. class PreviewDisplay : private TextureViewSurfaceTextureListener::Owner
  766. {
  767. public:
  768. struct Listener
  769. {
  770. virtual ~Listener() {}
  771. virtual void previewDisplayReady() = 0;
  772. virtual void previewDisplayAboutToBeDestroyed() = 0;
  773. };
  774. PreviewDisplay (Rectangle<int> bufferSize)
  775. : textureViewSurfaceTextureListener (*this),
  776. textureView (LocalRef<jobject> (getEnv()->NewObject (AndroidTextureView, AndroidTextureView.constructor,
  777. getAppContext().get()))),
  778. bufferWidth (bufferSize.getWidth()),
  779. bufferHeight (bufferSize.getHeight())
  780. {
  781. auto* env = getEnv();
  782. if (! isReady())
  783. env->CallVoidMethod (textureView, AndroidTextureView.setSurfaceTextureListener,
  784. CreateJavaInterface (&textureViewSurfaceTextureListener,
  785. "android/view/TextureView$SurfaceTextureListener").get());
  786. }
  787. ~PreviewDisplay() override
  788. {
  789. getEnv()->CallVoidMethod (textureView, AndroidTextureView.setSurfaceTextureListener, nullptr);
  790. }
  791. void addListener (Listener* l)
  792. {
  793. if (l == nullptr)
  794. {
  795. jassertfalse;
  796. return;
  797. }
  798. listeners.add (l);
  799. if (isReady())
  800. l->previewDisplayReady();
  801. }
  802. void removeListener (Listener* l)
  803. {
  804. if (l == nullptr)
  805. {
  806. jassertfalse;
  807. return;
  808. }
  809. listeners.remove (l);
  810. }
  811. bool isReady() const
  812. {
  813. return (getEnv()->CallBooleanMethod (textureView, AndroidTextureView.isAvailable) != 0)
  814. && width > 0 && height > 0;
  815. }
  816. LocalRef<jobject> createSurface()
  817. {
  818. // Surface may get destroyed while session is being configured, if
  819. // the preview gets hidden in the meantime, so bailout.
  820. if (! isReady())
  821. return LocalRef<jobject> (nullptr);
  822. auto* env = getEnv();
  823. auto surfaceTexture = LocalRef<jobject> (env->CallObjectMethod (textureView,
  824. AndroidTextureView.getSurfaceTexture));
  825. // NB: too small buffer will result in pixelated preview. A buffer with wrong aspect ratio
  826. // can result in a cropped preview.
  827. env->CallVoidMethod (surfaceTexture, AndroidSurfaceTexture.setDefaultBufferSize, (jint) bufferWidth, (jint) bufferHeight);
  828. auto surface = LocalRef<jobject> (env->NewObject (AndroidSurface, AndroidSurface.constructor, surfaceTexture.get()));
  829. return surface;
  830. }
  831. const GlobalRef& getNativeView() { return textureView; }
  832. void updateSurfaceTransform()
  833. {
  834. auto* env = getEnv();
  835. auto windowManager = LocalRef<jobject> (env->CallObjectMethod (getAppContext(), AndroidContext.getSystemService, javaString ("window").get()));
  836. auto display = LocalRef<jobject> (env->CallObjectMethod (windowManager, AndroidWindowManager.getDefaultDisplay));
  837. auto rotation = env->CallIntMethod (display, AndroidDisplay.getRotation);
  838. static constexpr int rotation90 = 1;
  839. static constexpr int rotation270 = 3;
  840. auto matrix = LocalRef<jobject> (env->NewObject (AndroidMatrix, AndroidMatrix.constructor));
  841. if (rotation == rotation90 || rotation == rotation270)
  842. {
  843. env->CallBooleanMethod (matrix, AndroidMatrix.postScale, jfloat (height / (float) width), jfloat (width / (float) height), (jfloat) 0, (jfloat) 0);
  844. env->CallBooleanMethod (matrix, AndroidMatrix.postRotate, (jfloat) 90 * (rotation - 2), (jfloat) 0, (jfloat) 0);
  845. env->CallBooleanMethod (matrix, AndroidMatrix.postTranslate, (jfloat) (rotation == 3 ? width : 0), (jfloat) (rotation == 1 ? height : 0));
  846. }
  847. env->CallVoidMethod (textureView, AndroidTextureView.setTransform, matrix.get());
  848. }
  849. private:
  850. ListenerList<Listener> listeners;
  851. TextureViewSurfaceTextureListener textureViewSurfaceTextureListener;
  852. GlobalRef textureView;
  853. int width = -1, height = -1;
  854. int bufferWidth, bufferHeight;
  855. void onSurfaceTextureAvailable (LocalRef<jobject>& /*surface*/, int widthToUse, int heightToUse) override
  856. {
  857. JUCE_CAMERA_LOG ("onSurfaceTextureAvailable()");
  858. width = widthToUse;
  859. height = heightToUse;
  860. updateSurfaceTransform();
  861. listeners.call (&Listener::previewDisplayReady);
  862. }
  863. bool onSurfaceTextureDestroyed (LocalRef<jobject>& /*surface*/) override
  864. {
  865. JUCE_CAMERA_LOG ("onSurfaceTextureDestroyed()");
  866. listeners.call (&Listener::previewDisplayAboutToBeDestroyed);
  867. return true;
  868. }
  869. void onSurfaceTextureSizeChanged (LocalRef<jobject>& /*surface*/, int widthToUse, int heightToUse) override
  870. {
  871. JUCE_CAMERA_LOG ("onSurfaceTextureSizeChanged()");
  872. width = widthToUse;
  873. height = heightToUse;
  874. updateSurfaceTransform();
  875. }
  876. void onSurfaceTextureUpdated (LocalRef<jobject>& /*surface*/) override
  877. {
  878. JUCE_CAMERA_LOG ("onSurfaceTextureUpdated()");
  879. }
  880. JUCE_DECLARE_NON_COPYABLE (PreviewDisplay)
  881. };
  882. //==============================================================================
  883. class ImageReader : private ImageReaderOnImageAvailableListener::Owner
  884. {
  885. public:
  886. ImageReader (Pimpl& ownerToUse, GlobalRef& handlerToUse,
  887. int imageWidth, int imageHeight, int cameraSensorOrientationToUse)
  888. : owner (ownerToUse),
  889. cameraSensorOrientation (cameraSensorOrientationToUse),
  890. imageReader (LocalRef<jobject> (getEnv()->CallStaticObjectMethod (AndroidImageReader, AndroidImageReader.newInstance,
  891. imageWidth, imageHeight, StreamConfigurationMap::jpegImageFormat,
  892. numImagesToKeep))),
  893. onImageAvailableListener (*this)
  894. {
  895. getEnv()->CallVoidMethod (imageReader, AndroidImageReader.setOnImageAvailableListener,
  896. CreateJavaInterface (&onImageAvailableListener,
  897. "android/media/ImageReader$OnImageAvailableListener").get(),
  898. handlerToUse.get());
  899. }
  900. ~ImageReader() override
  901. {
  902. getEnv()->CallVoidMethod (imageReader, AndroidImageReader.close);
  903. }
  904. LocalRef<jobject> getSurface() const
  905. {
  906. return LocalRef<jobject> (getEnv()->CallObjectMethod (imageReader, AndroidImageReader.getSurface));
  907. }
  908. void resetNotificationFlag()
  909. {
  910. hasNotifiedListeners.set (0);
  911. }
  912. private:
  913. Pimpl& owner;
  914. int cameraSensorOrientation;
  915. GlobalRef imageReader;
  916. ImageReaderOnImageAvailableListener onImageAvailableListener;
  917. static constexpr int numImagesToKeep = 2;
  918. Atomic<int> hasNotifiedListeners { 0 };
  919. JUCE_DECLARE_WEAK_REFERENCEABLE (ImageReader)
  920. void onImageAvailable (LocalRef<jobject>& /*imageReader*/) override
  921. {
  922. JUCE_CAMERA_LOG ("onImageAvailable()");
  923. auto* env = getEnv();
  924. auto jImage = LocalRef<jobject> (env->CallObjectMethod (imageReader, AndroidImageReader.acquireLatestImage));
  925. if (jImage.get() == nullptr)
  926. return;
  927. auto cameraLensFrontFacing = owner.getCameraLensFacing() == 0;
  928. // NB: could use sensor orientation here to get real-world orientation, but then the resulting
  929. // image could not match the UI orientation.
  930. auto image = androidImageToJuceWithFixedOrientation (jImage, owner.deviceOrientationChangeListener.getDeviceOrientation(),
  931. Desktop::getInstance().getCurrentOrientation(),
  932. cameraLensFrontFacing,
  933. cameraSensorOrientation);
  934. env->CallVoidMethod (jImage, AndroidImage.close);
  935. WeakReference<ImageReader> safeThis (this);
  936. owner.callListeners (image);
  937. // Android may take multiple pictures before it handles a request to stop.
  938. if (hasNotifiedListeners.compareAndSetBool (1, 0))
  939. MessageManager::callAsync ([safeThis, image]() mutable { if (safeThis != nullptr) safeThis->owner.notifyPictureTaken (image); });
  940. }
  941. struct ImageBuffer
  942. {
  943. LocalRef<jbyteArray> byteArray;
  944. int size;
  945. };
  946. static Image androidImageToJuceWithFixedOrientation (const LocalRef<jobject>& androidImage,
  947. Desktop::DisplayOrientation deviceOrientationFromAccelerometerSensor,
  948. Desktop::DisplayOrientation targetOrientation,
  949. bool cameraLensFrontFacing,
  950. int cameraSensorOrientation)
  951. {
  952. auto* env = getEnv();
  953. auto planes = LocalRef<jobjectArray> ((jobjectArray) env->CallObjectMethod (androidImage, AndroidImage.getPlanes));
  954. jassert (env->GetArrayLength (planes) > 0);
  955. auto plane = LocalRef<jobject> (env->GetObjectArrayElement (planes, 0));
  956. auto byteBuffer = LocalRef<jobject> (env->CallObjectMethod (plane, AndroidImagePlane.getBuffer));
  957. ImageBuffer correctedBuffer = getImageBufferWithCorrectedOrientationFrom (byteBuffer, deviceOrientationFromAccelerometerSensor,
  958. targetOrientation, cameraLensFrontFacing, cameraSensorOrientation);
  959. jbyte* rawBytes = env->GetByteArrayElements (correctedBuffer.byteArray, nullptr);
  960. Image result = ImageFileFormat::loadFrom (rawBytes, (size_t) correctedBuffer.size);
  961. env->ReleaseByteArrayElements (correctedBuffer.byteArray, rawBytes, 0);
  962. return result;
  963. }
  964. static ImageBuffer getImageBufferWithCorrectedOrientationFrom (const LocalRef<jobject>& imagePlaneBuffer,
  965. Desktop::DisplayOrientation deviceOrientationFromAccelerometerSensor,
  966. Desktop::DisplayOrientation targetOrientation,
  967. bool cameraLensFrontFacing,
  968. int cameraSensorOrientation)
  969. {
  970. auto* env = getEnv();
  971. auto bufferSize = env->CallIntMethod (imagePlaneBuffer, JavaByteBuffer.remaining);
  972. auto byteArray = LocalRef<jbyteArray> (env->NewByteArray (bufferSize));
  973. env->CallObjectMethod (imagePlaneBuffer, JavaByteBuffer.get, byteArray.get());
  974. auto rotationAngle = getRotationAngle (deviceOrientationFromAccelerometerSensor, targetOrientation,
  975. cameraLensFrontFacing, cameraSensorOrientation);
  976. if (rotationAngle == 0)
  977. {
  978. // Nothing to do, just get the bytes
  979. return { byteArray, bufferSize };
  980. }
  981. auto origBitmap = LocalRef<jobject> (env->CallStaticObjectMethod (AndroidBitmapFactory,
  982. AndroidBitmapFactory.decodeByteArray,
  983. byteArray.get(), (jint) 0, (jint) bufferSize));
  984. if (origBitmap == nullptr)
  985. {
  986. // Nothing to do, just get the bytes
  987. return { byteArray, bufferSize };
  988. }
  989. auto correctedBitmap = getBitmapWithCorrectOrientationFrom (origBitmap, rotationAngle);
  990. auto byteArrayOutputStream = LocalRef<jobject> (env->NewObject (ByteArrayOutputStream,
  991. ByteArrayOutputStream.constructor));
  992. auto jCompressFormatString = javaString ("JPEG");
  993. auto compressFormat = LocalRef<jobject> (env->CallStaticObjectMethod (AndroidBitmapCompressFormat,
  994. AndroidBitmapCompressFormat.valueOf,
  995. jCompressFormatString.get()));
  996. if (env->CallBooleanMethod (correctedBitmap, AndroidBitmap.compress, compressFormat.get(),
  997. (jint) 100, byteArrayOutputStream.get()) != 0)
  998. {
  999. auto correctedByteArray = LocalRef<jbyteArray> ((jbyteArray) env->CallObjectMethod (byteArrayOutputStream,
  1000. ByteArrayOutputStream.toByteArray));
  1001. int correctedByteArraySize = env->CallIntMethod (byteArrayOutputStream, ByteArrayOutputStream.size);
  1002. return { correctedByteArray, correctedByteArraySize };
  1003. }
  1004. jassertfalse;
  1005. // fallback, return original bitmap
  1006. return { byteArray, bufferSize };
  1007. }
  1008. static int getRotationAngle (Desktop::DisplayOrientation deviceOrientationFromAccelerometerSensor,
  1009. Desktop::DisplayOrientation targetOrientation,
  1010. bool cameraLensFrontFacing,
  1011. int cameraSensorOrientation)
  1012. {
  1013. auto isSensorOrientationHorizontal = deviceOrientationFromAccelerometerSensor == Desktop::rotatedAntiClockwise
  1014. || deviceOrientationFromAccelerometerSensor == Desktop::rotatedClockwise;
  1015. if (cameraLensFrontFacing && isSensorOrientationHorizontal)
  1016. {
  1017. // flip angles for front camera
  1018. return getRotationAngle (deviceOrientationFromAccelerometerSensor, targetOrientation, false, (cameraSensorOrientation + 180) % 360);
  1019. }
  1020. switch (targetOrientation)
  1021. {
  1022. case Desktop::rotatedAntiClockwise:
  1023. return cameraSensorOrientation == 90 ? 0 : 180;
  1024. case Desktop::rotatedClockwise:
  1025. return cameraSensorOrientation == 90 ? 180 : 0;
  1026. case Desktop::upright:
  1027. case Desktop::upsideDown:
  1028. if ((targetOrientation == Desktop::upright && ! cameraLensFrontFacing)
  1029. || (targetOrientation == Desktop::upsideDown && cameraLensFrontFacing))
  1030. {
  1031. return cameraSensorOrientation;
  1032. }
  1033. else
  1034. {
  1035. if (deviceOrientationFromAccelerometerSensor == Desktop::upright || deviceOrientationFromAccelerometerSensor == Desktop::upsideDown)
  1036. return cameraSensorOrientation;
  1037. else
  1038. return (cameraSensorOrientation + 180) % 360;
  1039. }
  1040. break;
  1041. case Desktop::allOrientations:
  1042. default:
  1043. return 0;
  1044. }
  1045. }
  1046. static LocalRef<jobject> getBitmapWithCorrectOrientationFrom (LocalRef<jobject>& origBitmap, int rotationAngle)
  1047. {
  1048. auto* env = getEnv();
  1049. auto origBitmapWidth = env->CallIntMethod (origBitmap, AndroidBitmap.getWidth);
  1050. auto origBitmapHeight = env->CallIntMethod (origBitmap, AndroidBitmap.getHeight);
  1051. auto matrix = LocalRef<jobject> (env->NewObject (AndroidMatrix, AndroidMatrix.constructor));
  1052. env->CallBooleanMethod (matrix, AndroidMatrix.postRotate, (jfloat) rotationAngle, (jfloat) 0, (jfloat) 0);
  1053. auto rotatedBitmap = LocalRef<jobject> (env->CallStaticObjectMethod (AndroidBitmap, AndroidBitmap.createBitmapFrom,
  1054. origBitmap.get(), (jint) 0, (jint) 0,
  1055. (jint) origBitmapWidth, (jint) origBitmapHeight,
  1056. matrix.get(), true));
  1057. env->CallVoidMethod (origBitmap, AndroidBitmap.recycle);
  1058. return rotatedBitmap;
  1059. }
  1060. };
  1061. //==============================================================================
  1062. class MediaRecorder : private MediaRecorderOnInfoListener::Owner,
  1063. private MediaRecorderOnErrorListener::Owner
  1064. {
  1065. public:
  1066. MediaRecorder (const String& outputFilePath, int videoWidth, int videoHeight,
  1067. int sensorOrientation, int cameraLensFacing)
  1068. : onInfoListener (*this),
  1069. onErrorListener (*this),
  1070. mediaRecorder (LocalRef<jobject> (getEnv()->NewObject (AndroidMediaRecorder,
  1071. AndroidMediaRecorder.constructor)))
  1072. {
  1073. auto* env = getEnv();
  1074. env->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setOnInfoListener,
  1075. CreateJavaInterface (&onInfoListener,
  1076. "android/media/MediaRecorder$OnInfoListener").get());
  1077. env->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setOnErrorListener,
  1078. CreateJavaInterface (&onErrorListener,
  1079. "android/media/MediaRecorder$OnErrorListener").get());
  1080. // NB: the order of function calls here is enforced, and exceptions will be thrown if
  1081. // the order is changed.
  1082. static constexpr int audioSourceMic = 1;
  1083. env->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setAudioSource, (jint) audioSourceMic);
  1084. static constexpr int videoSourceSurface = 2;
  1085. env->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setVideoSource, (jint) videoSourceSurface);
  1086. static constexpr int outputFormatMPEG4 = 2;
  1087. env->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setOutputFormat, (jint) outputFormatMPEG4);
  1088. static constexpr int audioEncoderAAC = 3;
  1089. env->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setAudioEncoder, (jint) audioEncoderAAC);
  1090. static constexpr int videoEncoderH264 = 2;
  1091. env->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setVideoEncoder, (jint) videoEncoderH264);
  1092. env->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setVideoEncodingBitRate, (jint) 10000000);
  1093. env->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setVideoFrameRate, (jint) 30);
  1094. auto frontFacing = cameraLensFacing == 0;
  1095. auto useInverseDegrees = frontFacing && sensorOrientation == 90;
  1096. int orientationHint = getOrientationHint (useInverseDegrees, sensorOrientation);
  1097. env->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setOrientationHint, (jint) orientationHint);
  1098. getEnv()->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setVideoSize, (jint) videoWidth, (jint) videoHeight);
  1099. getEnv()->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.setOutputFile, javaString (outputFilePath).get());
  1100. getEnv()->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.prepare);
  1101. }
  1102. ~MediaRecorder() override
  1103. {
  1104. getEnv()->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.release);
  1105. }
  1106. LocalRef<jobject> getSurface()
  1107. {
  1108. return LocalRef<jobject> (getEnv()->CallObjectMethod (mediaRecorder, AndroidMediaRecorder.getSurface));
  1109. }
  1110. void start()
  1111. {
  1112. lockScreenOrientation();
  1113. getEnv()->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.start);
  1114. hasStartedRecording = true;
  1115. }
  1116. void stop()
  1117. {
  1118. // A request to stop can be sent before recording has had a chance to start, so
  1119. // ignore the request rather than calling AndroidMediaRecorder.stop because
  1120. // otherwise MediaRecorder will throw an exception and...
  1121. if (! hasStartedRecording)
  1122. return;
  1123. hasStartedRecording = false;
  1124. auto* env = getEnv();
  1125. env->CallVoidMethod (mediaRecorder, AndroidMediaRecorder.stop);
  1126. // ... ignore RuntimeException that can be thrown if stop() was called after recording
  1127. // has started but before any frame was written to a file. This is not an error.
  1128. jniCheckHasExceptionOccurredAndClear();
  1129. unlockScreenOrientation();
  1130. }
  1131. private:
  1132. MediaRecorderOnInfoListener onInfoListener;
  1133. MediaRecorderOnErrorListener onErrorListener;
  1134. GlobalRef mediaRecorder;
  1135. bool hasStartedRecording = false;
  1136. int orientationsEnabled = -1;
  1137. void lockScreenOrientation()
  1138. {
  1139. orientationsEnabled = Desktop::getInstance().getOrientationsEnabled();
  1140. auto o = Desktop::getInstance().getCurrentOrientation();
  1141. Desktop::getInstance().setOrientationsEnabled (o);
  1142. }
  1143. static jint juceOrientationToNativeOrientation (int orientations) noexcept
  1144. {
  1145. enum
  1146. {
  1147. SCREEN_ORIENTATION_LANDSCAPE = 0,
  1148. SCREEN_ORIENTATION_PORTRAIT = 1,
  1149. SCREEN_ORIENTATION_USER = 2,
  1150. SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8,
  1151. SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9,
  1152. SCREEN_ORIENTATION_USER_LANDSCAPE = 11,
  1153. SCREEN_ORIENTATION_USER_PORTRAIT = 12,
  1154. };
  1155. switch (orientations)
  1156. {
  1157. case Desktop::upright: return (jint) SCREEN_ORIENTATION_PORTRAIT;
  1158. case Desktop::upsideDown: return (jint) SCREEN_ORIENTATION_REVERSE_PORTRAIT;
  1159. case Desktop::upright + Desktop::upsideDown: return (jint) SCREEN_ORIENTATION_USER_PORTRAIT;
  1160. case Desktop::rotatedAntiClockwise: return (jint) SCREEN_ORIENTATION_LANDSCAPE;
  1161. case Desktop::rotatedClockwise: return (jint) SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
  1162. case Desktop::rotatedClockwise + Desktop::rotatedAntiClockwise: return (jint) SCREEN_ORIENTATION_USER_LANDSCAPE;
  1163. default: return (jint) SCREEN_ORIENTATION_USER;
  1164. }
  1165. }
  1166. void unlockScreenOrientation()
  1167. {
  1168. Desktop::getInstance().setOrientationsEnabled (orientationsEnabled);
  1169. }
  1170. void onInfo (LocalRef<jobject>& recorder, int what, int extra) override
  1171. {
  1172. ignoreUnused (recorder, what, extra);
  1173. JUCE_CAMERA_LOG ("MediaRecorder::OnInfo: " + getInfoStringFromCode (what)
  1174. + ", extra code = " + String (extra));
  1175. }
  1176. void onError (LocalRef<jobject>& recorder, int what, int extra) override
  1177. {
  1178. ignoreUnused (recorder, what, extra);
  1179. JUCE_CAMERA_LOG ("MediaRecorder::onError: " + getErrorStringFromCode (what)
  1180. + ", extra code = " + String (extra));
  1181. }
  1182. static String getInfoStringFromCode (int what)
  1183. {
  1184. enum
  1185. {
  1186. MEDIA_RECORDER_INFO_UNKNOWN = 1,
  1187. MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800,
  1188. MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801,
  1189. MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING = 802,
  1190. MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED = 803
  1191. };
  1192. switch (what)
  1193. {
  1194. case MEDIA_RECORDER_INFO_UNKNOWN: return { "Unknown info" };
  1195. case MEDIA_RECORDER_INFO_MAX_DURATION_REACHED: return { "Max duration reached" };
  1196. case MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED: return { "Max filesize reached" };
  1197. case MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING: return { "Max filesize approaching" };
  1198. case MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED: return { "Next output file started" };
  1199. default: return String (what);
  1200. };
  1201. }
  1202. static String getErrorStringFromCode (int what)
  1203. {
  1204. enum
  1205. {
  1206. MEDIA_RECORDER_ERROR_UNKNOWN = 1,
  1207. MEDIA_ERROR_SERVER_DIED = 100
  1208. };
  1209. switch (what)
  1210. {
  1211. case MEDIA_RECORDER_ERROR_UNKNOWN: return { "Unknown error" };
  1212. case MEDIA_ERROR_SERVER_DIED: return { "Server died" };
  1213. default: return String (what);
  1214. };
  1215. }
  1216. static int getOrientationHint (bool useInverseDegrees, int cameraSensorOrientation)
  1217. {
  1218. auto* env = getEnv();
  1219. auto windowManager = LocalRef<jobject> (env->CallObjectMethod (getAppContext(), AndroidContext.getSystemService, javaString ("window").get()));
  1220. auto display = LocalRef<jobject> (env->CallObjectMethod (windowManager, AndroidWindowManager.getDefaultDisplay));
  1221. auto rotation = env->CallIntMethod (display, AndroidDisplay.getRotation);
  1222. enum
  1223. {
  1224. ROTATION_0 = 0,
  1225. ROTATION_90,
  1226. ROTATION_180,
  1227. ROTATION_270
  1228. };
  1229. int hint = 0;
  1230. switch (rotation)
  1231. {
  1232. case ROTATION_0: hint = cameraSensorOrientation; break;
  1233. case ROTATION_90: hint = useInverseDegrees ? 180 : 0; break;
  1234. case ROTATION_180: hint = cameraSensorOrientation + 180; break;
  1235. case ROTATION_270: hint = useInverseDegrees ? 0 : 180; break;
  1236. default: jassertfalse;
  1237. }
  1238. return (hint + 360) % 360;
  1239. }
  1240. };
  1241. //==============================================================================
  1242. class ScopedCameraDevice
  1243. {
  1244. public:
  1245. //==============================================================================
  1246. class CaptureSession
  1247. {
  1248. public:
  1249. struct ConfiguredCallback
  1250. {
  1251. virtual ~ConfiguredCallback() {}
  1252. virtual void captureSessionConfigured (CaptureSession*) = 0;
  1253. };
  1254. ~CaptureSession()
  1255. {
  1256. bool calledClose = false;
  1257. auto* env = getEnv();
  1258. {
  1259. const ScopedLock lock (captureSessionLock);
  1260. if (captureSession.get() != nullptr)
  1261. {
  1262. calledClose = true;
  1263. env->CallVoidMethod (captureSession, CameraCaptureSession.close);
  1264. }
  1265. }
  1266. // When exception occurs, CameraCaptureSession.close will never finish, so
  1267. // we should not wait for it. For fatal error an exception does occur, but
  1268. // it is caught internally in Java...
  1269. if (jniCheckHasExceptionOccurredAndClear() || scopedCameraDevice.fatalErrorOccurred.get())
  1270. {
  1271. JUCE_CAMERA_LOG ("Exception or fatal error occurred while closing Capture Session, closing by force");
  1272. }
  1273. else if (calledClose)
  1274. {
  1275. pendingClose.set (1);
  1276. closedEvent.wait (-1);
  1277. }
  1278. }
  1279. bool openedOk() const noexcept { return captureSession != nullptr; }
  1280. const GlobalRef& getNativeSession() const { return captureSession; }
  1281. bool start (const LocalRef<jobject>& targetSurfacesList, GlobalRef& handlerToUse)
  1282. {
  1283. if (! openedOk())
  1284. {
  1285. jassertfalse;
  1286. return false;
  1287. }
  1288. auto* env = getEnv();
  1289. auto numSurfaces = env->CallIntMethod (targetSurfacesList, JavaArrayList.size);
  1290. for (int i = 0; i < numSurfaces; ++i)
  1291. {
  1292. auto surface = LocalRef<jobject> (env->CallObjectMethod (targetSurfacesList, JavaArrayList.get, (jint) i));
  1293. env->CallVoidMethod (captureRequestBuilder, CaptureRequestBuilder.addTarget, surface.get());
  1294. }
  1295. previewCaptureRequest = GlobalRef (LocalRef<jobject>(env->CallObjectMethod (captureRequestBuilder, CaptureRequestBuilder.build)));
  1296. env->CallIntMethod (captureSession, CameraCaptureSession.setRepeatingRequest,
  1297. previewCaptureRequest.get(), nullptr, handlerToUse.get());
  1298. return true;
  1299. }
  1300. void takeStillPicture (jobject targetSurface)
  1301. {
  1302. if (stillPictureTaker == nullptr)
  1303. {
  1304. // Can only take picture once session was successfully configured!
  1305. jassertfalse;
  1306. return;
  1307. }
  1308. auto* env = getEnv();
  1309. static constexpr int templateStillCapture = 2;
  1310. auto builder = LocalRef<jobject> (env->CallObjectMethod (scopedCameraDevice.cameraDevice,
  1311. AndroidCameraDevice.createCaptureRequest,
  1312. (jint) templateStillCapture));
  1313. env->CallVoidMethod (builder, CaptureRequestBuilder.addTarget, targetSurface);
  1314. setCaptureRequestBuilderIntegerKey (builder, CaptureRequest.CONTROL_AF_MODE, autoFocusMode);
  1315. auto stillPictureCaptureRequest = LocalRef<jobject> (env->CallObjectMethod (builder, CaptureRequestBuilder.build));
  1316. stillPictureTaker->takePicture (stillPictureCaptureRequest);
  1317. }
  1318. private:
  1319. //==============================================================================
  1320. class StillPictureTaker : private AndroidRunnable::Owner
  1321. {
  1322. public:
  1323. StillPictureTaker (GlobalRef& captureSessionToUse, GlobalRef& captureRequestBuilderToUse,
  1324. GlobalRef& previewCaptureRequestToUse, GlobalRef& handlerToUse,
  1325. int autoFocusModeToUse)
  1326. : captureSession (captureSessionToUse),
  1327. captureRequestBuilder (captureRequestBuilderToUse),
  1328. previewCaptureRequest (previewCaptureRequestToUse),
  1329. handler (handlerToUse),
  1330. runnable (*this),
  1331. captureSessionPreviewCaptureCallback (createCaptureSessionCallback (true)),
  1332. captureSessionStillPictureCaptureCallback (createCaptureSessionCallback (false)),
  1333. autoFocusMode (autoFocusModeToUse)
  1334. {
  1335. }
  1336. void takePicture (const LocalRef<jobject>& stillPictureCaptureRequestToUse)
  1337. {
  1338. JUCE_CAMERA_LOG ("Taking picture...");
  1339. stillPictureCaptureRequest = GlobalRef (LocalRef<jobject>(stillPictureCaptureRequestToUse));
  1340. lockFocus();
  1341. }
  1342. private:
  1343. GlobalRef& captureSession;
  1344. GlobalRef& captureRequestBuilder;
  1345. GlobalRef& previewCaptureRequest;
  1346. GlobalRef& handler;
  1347. AndroidRunnable runnable;
  1348. GlobalRef delayedCaptureRunnable;
  1349. GlobalRef captureSessionPreviewCaptureCallback;
  1350. GlobalRef stillPictureCaptureRequest;
  1351. GlobalRef captureSessionStillPictureCaptureCallback;
  1352. int autoFocusMode;
  1353. //==============================================================================
  1354. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  1355. METHOD (constructor, "<init>", "(JZ)V") \
  1356. CALLBACK (cameraCaptureSessionCaptureCompletedCallback, "cameraCaptureSessionCaptureCompleted", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;Landroid/hardware/camera2/TotalCaptureResult;)V") \
  1357. CALLBACK (cameraCaptureSessionCaptureFailedCallback, "cameraCaptureSessionCaptureFailed", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;Landroid/hardware/camera2/CaptureFailure;)V") \
  1358. CALLBACK (cameraCaptureSessionCaptureProgressedCallback, "cameraCaptureSessionCaptureProgressed", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;Landroid/hardware/camera2/CaptureResult;)V") \
  1359. CALLBACK (cameraCaptureSessionCaptureStartedCallback, "cameraCaptureSessionCaptureStarted", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;JJ)V") \
  1360. CALLBACK (cameraCaptureSessionCaptureSequenceAbortedCallback, "cameraCaptureSessionCaptureSequenceAborted", "(JZLandroid/hardware/camera2/CameraCaptureSession;I)V") \
  1361. CALLBACK (cameraCaptureSessionCaptureSequenceCompletedCallback, "cameraCaptureSessionCaptureSequenceCompleted", "(JZLandroid/hardware/camera2/CameraCaptureSession;IJ)V")
  1362. DECLARE_JNI_CLASS_WITH_BYTECODE (CameraCaptureSessionCaptureCallback, "com/rmsl/juce/CameraCaptureSessionCaptureCallback", 21, CameraSupportByteCode, sizeof(CameraSupportByteCode))
  1363. #undef JNI_CLASS_MEMBERS
  1364. LocalRef<jobject> createCaptureSessionCallback (bool createPreviewSession)
  1365. {
  1366. return LocalRef<jobject>(getEnv()->NewObject (CameraCaptureSessionCaptureCallback,
  1367. CameraCaptureSessionCaptureCallback.constructor,
  1368. reinterpret_cast<jlong> (this),
  1369. createPreviewSession ? 1 : 0));
  1370. }
  1371. //==============================================================================
  1372. enum class State
  1373. {
  1374. idle = 0,
  1375. pendingFocusLock,
  1376. pendingExposurePrecapture,
  1377. pendingExposurePostPrecapture,
  1378. pictureTaken
  1379. };
  1380. State currentState = State::idle;
  1381. void lockFocus()
  1382. {
  1383. if (jniCheckHasExceptionOccurredAndClear())
  1384. return;
  1385. JUCE_CAMERA_LOG ("Performing auto-focus if possible...");
  1386. currentState = State::pendingFocusLock;
  1387. auto* env = getEnv();
  1388. // NB: auto-focus may be unavailable on a device, in which case it may have already
  1389. // automatically adjusted the exposure. We check for that in updateState().
  1390. static constexpr int controlAfTriggerStart = 1;
  1391. CaptureSession::setCaptureRequestBuilderIntegerKey (captureRequestBuilder.get(),
  1392. CaptureRequest.CONTROL_AF_TRIGGER,
  1393. controlAfTriggerStart);
  1394. auto previewRequest = LocalRef<jobject> (env->CallObjectMethod (captureRequestBuilder,
  1395. CaptureRequestBuilder.build));
  1396. env->CallIntMethod (captureSession, CameraCaptureSession.capture, previewRequest.get(),
  1397. captureSessionPreviewCaptureCallback.get(), handler.get());
  1398. }
  1399. void updateState (jobject captureResult)
  1400. {
  1401. // IllegalStateException can be thrown when accessing CaptureSession,
  1402. // claiming that capture session was already closed but we may not
  1403. // get relevant callback yet, so check for this and bailout when needed.
  1404. if (jniCheckHasExceptionOccurredAndClear())
  1405. return;
  1406. switch (currentState)
  1407. {
  1408. case State::pendingFocusLock:
  1409. {
  1410. JUCE_CAMERA_LOG ("Still picture capture, updateState(), State::pendingFocusLock...");
  1411. auto controlAfStateValue = getCaptureResultIntegerKeyValue (CaptureResult.CONTROL_AF_STATE, captureResult);
  1412. if (controlAfStateValue.get() == nullptr)
  1413. {
  1414. captureStillPictureDelayed();
  1415. return;
  1416. }
  1417. auto autoToFocusNotAvailable = autoFocusMode == 0;
  1418. if (autoToFocusNotAvailable || autoFocusHasFinished (controlAfStateValue))
  1419. {
  1420. auto controlAeStateIntValue = getControlAEState (captureResult);
  1421. static constexpr int controlAeStateConverged = 2;
  1422. if (controlAeStateIntValue == -1 || controlAeStateIntValue == controlAeStateConverged)
  1423. {
  1424. currentState = State::pictureTaken;
  1425. captureStillPictureDelayed();
  1426. }
  1427. else
  1428. {
  1429. runPrecaptureSequence();
  1430. }
  1431. }
  1432. break;
  1433. }
  1434. case State::pendingExposurePrecapture:
  1435. {
  1436. JUCE_CAMERA_LOG ("Still picture capture, updateState(), State::pendingExposurePrecapture...");
  1437. auto controlAeStateIntValue = getControlAEState (captureResult);
  1438. static constexpr int controlAeStateFlashRequired = 4;
  1439. static constexpr int controlAeStatePrecapture = 5;
  1440. if (controlAeStateIntValue == -1 || controlAeStateIntValue == controlAeStateFlashRequired
  1441. || controlAeStateIntValue == controlAeStatePrecapture)
  1442. {
  1443. currentState = State::pendingExposurePostPrecapture;
  1444. }
  1445. break;
  1446. }
  1447. case State::pendingExposurePostPrecapture:
  1448. {
  1449. JUCE_CAMERA_LOG ("Still picture capture, updateState(), State::pendingExposurePostPrecapture...");
  1450. auto controlAeStateIntValue = getControlAEState (captureResult);
  1451. static constexpr int controlAeStatePrecapture = 5;
  1452. if (controlAeStateIntValue == -1 || controlAeStateIntValue != controlAeStatePrecapture)
  1453. {
  1454. currentState = State::pictureTaken;
  1455. captureStillPictureDelayed();
  1456. }
  1457. break;
  1458. }
  1459. case State::idle:
  1460. case State::pictureTaken:
  1461. { /* do nothing */ break; }
  1462. };
  1463. }
  1464. static int getControlAEState (jobject captureResult)
  1465. {
  1466. auto controlAeStateValue = getCaptureResultIntegerKeyValue (CaptureResult.CONTROL_AE_STATE, captureResult);
  1467. return controlAeStateValue.get() != nullptr
  1468. ? getEnv()->CallIntMethod (controlAeStateValue, JavaInteger.intValue) : -1;
  1469. }
  1470. static bool autoFocusHasFinished (const LocalRef<jobject>& controlAfStateValue)
  1471. {
  1472. static constexpr int controlAfStateFocusedLocked = 4;
  1473. static constexpr int controlAfStateNotFocusedLocked = 5;
  1474. auto controlAfStateIntValue = getEnv()->CallIntMethod (controlAfStateValue, JavaInteger.intValue);
  1475. return controlAfStateIntValue == controlAfStateFocusedLocked || controlAfStateIntValue == controlAfStateNotFocusedLocked;
  1476. }
  1477. static LocalRef<jobject> getCaptureResultIntegerKeyValue (jfieldID key, jobject captureResult)
  1478. {
  1479. auto* env = getEnv();
  1480. auto jKey = LocalRef<jobject> (env->GetStaticObjectField (CaptureResult, key));
  1481. return LocalRef<jobject> (env->CallObjectMethod (captureResult, CaptureResult.get, jKey.get()));
  1482. }
  1483. void captureStillPictureDelayed()
  1484. {
  1485. if (jniCheckHasExceptionOccurredAndClear())
  1486. return;
  1487. JUCE_CAMERA_LOG ("Still picture capture, device ready, capturing now...");
  1488. auto* env = getEnv();
  1489. env->CallVoidMethod (captureSession, CameraCaptureSession.stopRepeating);
  1490. if (jniCheckHasExceptionOccurredAndClear())
  1491. return;
  1492. env->CallVoidMethod (captureSession, CameraCaptureSession.abortCaptures);
  1493. if (jniCheckHasExceptionOccurredAndClear())
  1494. return;
  1495. // Delay still picture capture for devices that can't handle it right after
  1496. // stopRepeating/abortCaptures calls.
  1497. if (delayedCaptureRunnable.get() == nullptr)
  1498. delayedCaptureRunnable = GlobalRef (CreateJavaInterface (&runnable, "java/lang/Runnable"));
  1499. env->CallBooleanMethod (handler, AndroidHandler.postDelayed, delayedCaptureRunnable.get(), (jlong) 200);
  1500. }
  1501. void runPrecaptureSequence()
  1502. {
  1503. if (jniCheckHasExceptionOccurredAndClear())
  1504. return;
  1505. auto* env = getEnv();
  1506. static constexpr int controlAePrecaptureTriggerStart = 1;
  1507. CaptureSession::setCaptureRequestBuilderIntegerKey (captureRequestBuilder.get(),
  1508. CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
  1509. controlAePrecaptureTriggerStart);
  1510. currentState = State::pendingExposurePrecapture;
  1511. auto previewRequest = LocalRef<jobject> (env->CallObjectMethod (captureRequestBuilder,
  1512. CaptureRequestBuilder.build));
  1513. env->CallIntMethod (captureSession, CameraCaptureSession.capture, previewRequest.get(),
  1514. captureSessionPreviewCaptureCallback.get(), handler.get());
  1515. }
  1516. void unlockFocus()
  1517. {
  1518. if (jniCheckHasExceptionOccurredAndClear())
  1519. return;
  1520. JUCE_CAMERA_LOG ("Unlocking focus...");
  1521. currentState = State::idle;
  1522. auto* env = getEnv();
  1523. static constexpr int controlAfTriggerCancel = 2;
  1524. CaptureSession::setCaptureRequestBuilderIntegerKey (captureRequestBuilder.get(),
  1525. CaptureRequest.CONTROL_AF_TRIGGER,
  1526. controlAfTriggerCancel);
  1527. auto resetAutoFocusRequest = LocalRef<jobject> (env->CallObjectMethod (captureRequestBuilder,
  1528. CaptureRequestBuilder.build));
  1529. env->CallIntMethod (captureSession, CameraCaptureSession.capture, resetAutoFocusRequest.get(),
  1530. nullptr, handler.get());
  1531. if (jniCheckHasExceptionOccurredAndClear())
  1532. return;
  1533. // NB: for preview, using preview capture request again
  1534. env->CallIntMethod (captureSession, CameraCaptureSession.setRepeatingRequest, previewCaptureRequest.get(),
  1535. nullptr, handler.get());
  1536. }
  1537. //==============================================================================
  1538. void run() override
  1539. {
  1540. captureStillPicture();
  1541. }
  1542. void captureStillPicture()
  1543. {
  1544. getEnv()->CallIntMethod (captureSession, CameraCaptureSession.capture,
  1545. stillPictureCaptureRequest.get(), captureSessionStillPictureCaptureCallback.get(),
  1546. nullptr);
  1547. }
  1548. //==============================================================================
  1549. void cameraCaptureSessionCaptureCompleted (bool isPreview, jobject session, jobject request, jobject result)
  1550. {
  1551. JUCE_CAMERA_LOG ("cameraCaptureSessionCaptureCompleted()");
  1552. ignoreUnused (session, request);
  1553. if (isPreview)
  1554. updateState (result);
  1555. else if (currentState != State::idle)
  1556. unlockFocus();
  1557. }
  1558. void cameraCaptureSessionCaptureFailed (bool isPreview, jobject session, jobject request, jobject failure)
  1559. {
  1560. JUCE_CAMERA_LOG ("cameraCaptureSessionCaptureFailed()");
  1561. ignoreUnused (isPreview, session, request, failure);
  1562. }
  1563. void cameraCaptureSessionCaptureProgressed (bool isPreview, jobject session, jobject request, jobject partialResult)
  1564. {
  1565. JUCE_CAMERA_LOG ("cameraCaptureSessionCaptureProgressed()");
  1566. ignoreUnused (session, request);
  1567. if (isPreview)
  1568. updateState (partialResult);
  1569. }
  1570. void cameraCaptureSessionCaptureSequenceAborted (bool isPreview, jobject session, int sequenceId)
  1571. {
  1572. JUCE_CAMERA_LOG ("cameraCaptureSessionCaptureSequenceAborted()");
  1573. ignoreUnused (isPreview, isPreview, session, sequenceId);
  1574. }
  1575. void cameraCaptureSessionCaptureSequenceCompleted (bool isPreview, jobject session, int sequenceId, int64 frameNumber)
  1576. {
  1577. JUCE_CAMERA_LOG ("cameraCaptureSessionCaptureSequenceCompleted()");
  1578. ignoreUnused (isPreview, session, sequenceId, frameNumber);
  1579. }
  1580. void cameraCaptureSessionCaptureStarted (bool isPreview, jobject session, jobject request, int64 timestamp, int64 frameNumber)
  1581. {
  1582. JUCE_CAMERA_LOG ("cameraCaptureSessionCaptureStarted()");
  1583. ignoreUnused (isPreview, session, request, timestamp, frameNumber);
  1584. }
  1585. //==============================================================================
  1586. static void cameraCaptureSessionCaptureCompletedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jobject rawRequest, jobject rawResult)
  1587. {
  1588. if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
  1589. {
  1590. LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
  1591. LocalRef<jobject> request (getEnv()->NewLocalRef(rawRequest));
  1592. LocalRef<jobject> result (getEnv()->NewLocalRef(rawResult));
  1593. myself->cameraCaptureSessionCaptureCompleted (isPreview != 0, session, request, result);
  1594. }
  1595. }
  1596. static void cameraCaptureSessionCaptureFailedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jobject rawRequest, jobject rawResult)
  1597. {
  1598. if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
  1599. {
  1600. LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
  1601. LocalRef<jobject> request (getEnv()->NewLocalRef(rawRequest));
  1602. LocalRef<jobject> result (getEnv()->NewLocalRef(rawResult));
  1603. myself->cameraCaptureSessionCaptureFailed (isPreview != 0, session, request, result);
  1604. }
  1605. }
  1606. static void cameraCaptureSessionCaptureProgressedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jobject rawRequest, jobject rawResult)
  1607. {
  1608. if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
  1609. {
  1610. LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
  1611. LocalRef<jobject> request (getEnv()->NewLocalRef(rawRequest));
  1612. LocalRef<jobject> result (getEnv()->NewLocalRef(rawResult));
  1613. myself->cameraCaptureSessionCaptureProgressed (isPreview != 0, session, request, result);
  1614. }
  1615. }
  1616. static void cameraCaptureSessionCaptureSequenceAbortedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jint sequenceId)
  1617. {
  1618. if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
  1619. {
  1620. LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
  1621. myself->cameraCaptureSessionCaptureSequenceAborted (isPreview != 0, session, sequenceId);
  1622. }
  1623. }
  1624. static void cameraCaptureSessionCaptureSequenceCompletedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jint sequenceId, jlong frameNumber)
  1625. {
  1626. if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
  1627. {
  1628. LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
  1629. myself->cameraCaptureSessionCaptureSequenceCompleted (isPreview != 0, session, sequenceId, frameNumber);
  1630. }
  1631. }
  1632. static void cameraCaptureSessionCaptureStartedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jobject rawRequest, jlong timestamp, jlong frameNumber)
  1633. {
  1634. if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
  1635. {
  1636. LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
  1637. LocalRef<jobject> request (getEnv()->NewLocalRef(rawRequest));
  1638. myself->cameraCaptureSessionCaptureStarted (isPreview != 0, session, request, timestamp, frameNumber);
  1639. }
  1640. }
  1641. };
  1642. //==============================================================================
  1643. ScopedCameraDevice& scopedCameraDevice;
  1644. ConfiguredCallback& configuredCallback;
  1645. GlobalRef& handler;
  1646. GlobalRef captureRequestBuilder;
  1647. GlobalRef previewCaptureRequest;
  1648. GlobalRef captureSessionStateCallback;
  1649. int autoFocusMode;
  1650. GlobalRef captureSession;
  1651. CriticalSection captureSessionLock;
  1652. Atomic<int> pendingClose { 0 };
  1653. std::unique_ptr<StillPictureTaker> stillPictureTaker;
  1654. WaitableEvent closedEvent;
  1655. JUCE_DECLARE_WEAK_REFERENCEABLE (CaptureSession)
  1656. //==============================================================================
  1657. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  1658. METHOD (constructor, "<init>", "(J)V") \
  1659. CALLBACK(cameraCaptureSessionActiveCallback, "cameraCaptureSessionActive", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
  1660. CALLBACK(cameraCaptureSessionClosedCallback, "cameraCaptureSessionClosed", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
  1661. CALLBACK(cameraCaptureSessionConfigureFailedCallback, "cameraCaptureSessionConfigureFailed", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
  1662. CALLBACK(cameraCaptureSessionConfiguredCallback, "cameraCaptureSessionConfigured", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
  1663. CALLBACK(cameraCaptureSessionReadyCallback, "cameraCaptureSessionReady", "(JLandroid/hardware/camera2/CameraCaptureSession;)V")
  1664. DECLARE_JNI_CLASS_WITH_MIN_SDK (CameraCaptureSessionStateCallback, "com/rmsl/juce/CameraCaptureSessionStateCallback", 21)
  1665. #undef JNI_CLASS_MEMBERS
  1666. //==============================================================================
  1667. CaptureSession (ScopedCameraDevice& scopedCameraDeviceToUse, ConfiguredCallback& configuredCallbackToUse,
  1668. const LocalRef<jobject>& surfacesList, GlobalRef& handlerToUse,
  1669. int captureSessionTemplate, int autoFocusModeToUse)
  1670. : scopedCameraDevice (scopedCameraDeviceToUse),
  1671. configuredCallback (configuredCallbackToUse),
  1672. handler (handlerToUse),
  1673. captureRequestBuilder (LocalRef<jobject> (getEnv()->CallObjectMethod (scopedCameraDevice.cameraDevice,
  1674. AndroidCameraDevice.createCaptureRequest,
  1675. (jint) captureSessionTemplate))),
  1676. captureSessionStateCallback (LocalRef<jobject> (getEnv()->NewObject (CameraCaptureSessionStateCallback,
  1677. CameraCaptureSessionStateCallback.constructor,
  1678. reinterpret_cast<jlong> (this)))),
  1679. autoFocusMode (autoFocusModeToUse)
  1680. {
  1681. auto* env = getEnv();
  1682. env->CallVoidMethod (scopedCameraDevice.cameraDevice, AndroidCameraDevice.createCaptureSession,
  1683. surfacesList.get(), captureSessionStateCallback.get(), handler.get());
  1684. static constexpr int controlModeAuto = 1;
  1685. setCaptureRequestBuilderIntegerKey (captureRequestBuilder.get(), CaptureRequest.CONTROL_MODE, controlModeAuto);
  1686. setCaptureRequestBuilderIntegerKey (captureRequestBuilder.get(), CaptureRequest.CONTROL_AF_MODE, autoFocusMode);
  1687. }
  1688. static void setCaptureRequestBuilderIntegerKey (jobject captureRequestBuilder, jfieldID key, int value)
  1689. {
  1690. auto* env = getEnv();
  1691. auto jKey = LocalRef<jobject> (env->GetStaticObjectField (CaptureRequest, key));
  1692. auto jValue = LocalRef<jobject> (env->CallStaticObjectMethod (JavaInteger, JavaInteger.valueOf, (jint) value));
  1693. env->CallVoidMethod (captureRequestBuilder, CaptureRequestBuilder.set, jKey.get(), jValue.get());
  1694. }
  1695. void cameraCaptureSessionActive (jobject session)
  1696. {
  1697. JUCE_CAMERA_LOG ("cameraCaptureSessionActive()");
  1698. ignoreUnused (session);
  1699. }
  1700. void cameraCaptureSessionClosed (jobject session)
  1701. {
  1702. JUCE_CAMERA_LOG ("cameraCaptureSessionClosed()");
  1703. ignoreUnused (session);
  1704. closedEvent.signal();
  1705. }
  1706. void cameraCaptureSessionConfigureFailed (jobject session)
  1707. {
  1708. JUCE_CAMERA_LOG ("cameraCaptureSessionConfigureFailed()");
  1709. ignoreUnused (session);
  1710. WeakReference<CaptureSession> weakRef (this);
  1711. MessageManager::callAsync ([this, weakRef]()
  1712. {
  1713. if (weakRef == nullptr)
  1714. return;
  1715. configuredCallback.captureSessionConfigured (nullptr);
  1716. });
  1717. }
  1718. void cameraCaptureSessionConfigured (const LocalRef<jobject>& session)
  1719. {
  1720. JUCE_CAMERA_LOG ("cameraCaptureSessionConfigured()");
  1721. if (pendingClose.get() == 1)
  1722. {
  1723. // Already closing, bailout.
  1724. closedEvent.signal();
  1725. GlobalRef s (session);
  1726. MessageManager::callAsync ([s]()
  1727. {
  1728. getEnv()->CallVoidMethod (s, CameraCaptureSession.close);
  1729. });
  1730. return;
  1731. }
  1732. {
  1733. const ScopedLock lock (captureSessionLock);
  1734. captureSession = GlobalRef (session);
  1735. }
  1736. WeakReference<CaptureSession> weakRef (this);
  1737. MessageManager::callAsync ([this, weakRef]()
  1738. {
  1739. if (weakRef == nullptr)
  1740. return;
  1741. stillPictureTaker.reset (new StillPictureTaker (captureSession, captureRequestBuilder,
  1742. previewCaptureRequest, handler, autoFocusMode));
  1743. configuredCallback.captureSessionConfigured (this);
  1744. });
  1745. }
  1746. void cameraCaptureSessionReady (const LocalRef<jobject>& session)
  1747. {
  1748. JUCE_CAMERA_LOG ("cameraCaptureSessionReady()");
  1749. ignoreUnused (session);
  1750. }
  1751. //==============================================================================
  1752. static void cameraCaptureSessionActiveCallback (JNIEnv*, jobject, jlong host, jobject rawSession)
  1753. {
  1754. if (auto* myself = reinterpret_cast<CaptureSession*> (host))
  1755. {
  1756. LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
  1757. myself->cameraCaptureSessionActive (session);
  1758. }
  1759. }
  1760. static void cameraCaptureSessionClosedCallback (JNIEnv*, jobject, jlong host, jobject rawSession)
  1761. {
  1762. if (auto* myself = reinterpret_cast<CaptureSession*> (host))
  1763. {
  1764. LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
  1765. myself->cameraCaptureSessionClosed (session);
  1766. }
  1767. }
  1768. static void cameraCaptureSessionConfigureFailedCallback (JNIEnv*, jobject, jlong host, jobject rawSession)
  1769. {
  1770. if (auto* myself = reinterpret_cast<CaptureSession*> (host))
  1771. {
  1772. LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
  1773. myself->cameraCaptureSessionConfigureFailed (session);
  1774. }
  1775. }
  1776. static void cameraCaptureSessionConfiguredCallback (JNIEnv*, jobject, jlong host, jobject rawSession)
  1777. {
  1778. if (auto* myself = reinterpret_cast<CaptureSession*> (host))
  1779. {
  1780. LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
  1781. myself->cameraCaptureSessionConfigured (session);
  1782. }
  1783. }
  1784. static void cameraCaptureSessionReadyCallback (JNIEnv*, jobject, jlong host, jobject rawSession)
  1785. {
  1786. if (auto* myself = reinterpret_cast<CaptureSession*> (host))
  1787. {
  1788. LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
  1789. myself->cameraCaptureSessionReady (session);
  1790. }
  1791. }
  1792. //==============================================================================
  1793. friend class ScopedCameraDevice;
  1794. JUCE_DECLARE_NON_COPYABLE (CaptureSession)
  1795. };
  1796. //==============================================================================
  1797. ScopedCameraDevice (Pimpl& ownerToUse, const String& cameraIdToUse, GlobalRef& cameraManagerToUse,
  1798. GlobalRef& handlerToUse, int autoFocusModeToUse)
  1799. : owner (ownerToUse),
  1800. cameraId (cameraIdToUse),
  1801. cameraManager (cameraManagerToUse),
  1802. handler (handlerToUse),
  1803. cameraStateCallback (createCameraStateCallbackObject()),
  1804. autoFocusMode (autoFocusModeToUse)
  1805. {
  1806. open();
  1807. }
  1808. ~ScopedCameraDevice()
  1809. {
  1810. close();
  1811. }
  1812. void open()
  1813. {
  1814. pendingOpen.set (1);
  1815. auto* env = getEnv();
  1816. env->CallVoidMethod (cameraManager, CameraManager.openCamera,
  1817. javaString (cameraId).get(),
  1818. cameraStateCallback.get(), handler.get());
  1819. // If something went wrong we will be pinged in cameraDeviceStateError()
  1820. // callback, silence the redundant exception.
  1821. jniCheckHasExceptionOccurredAndClear();
  1822. }
  1823. void close()
  1824. {
  1825. if (pendingClose.compareAndSetBool (1, 0))
  1826. {
  1827. auto* env = getEnv();
  1828. if (cameraDevice.get() != nullptr)
  1829. {
  1830. env->CallVoidMethod (cameraDevice, AndroidCameraDevice.close);
  1831. closedEvent.wait (-1);
  1832. }
  1833. pendingClose.set (0);
  1834. pendingOpen .set (0);
  1835. cameraDevice.clear();
  1836. }
  1837. }
  1838. bool openedOk() const { return cameraDevice != nullptr; }
  1839. bool hasErrorOccurred() const { return fatalErrorOccurred.get(); }
  1840. CaptureSession* createCaptureSession (CaptureSession::ConfiguredCallback& cc,
  1841. const LocalRef<jobject>& surfacesList,
  1842. GlobalRef& handlerToUse,
  1843. int captureSessionTemplate)
  1844. {
  1845. if (! openedOk())
  1846. {
  1847. jassertfalse;
  1848. return nullptr;
  1849. }
  1850. return new CaptureSession (*this, cc, surfacesList, handlerToUse, captureSessionTemplate, autoFocusMode);
  1851. }
  1852. private:
  1853. Pimpl& owner;
  1854. const String cameraId;
  1855. GlobalRef& cameraManager;
  1856. GlobalRef& handler;
  1857. GlobalRef cameraStateCallback;
  1858. int autoFocusMode;
  1859. GlobalRef cameraDevice;
  1860. Atomic<int> pendingOpen { 0 };
  1861. Atomic<int> pendingClose { 0 };
  1862. Atomic<int> fatalErrorOccurred { 0 };
  1863. String openError;
  1864. WaitableEvent closedEvent;
  1865. //==============================================================================
  1866. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  1867. METHOD (constructor, "<init>", "(J)V") \
  1868. CALLBACK (cameraDeviceStateClosedCallback, "cameraDeviceStateClosed", "(JLandroid/hardware/camera2/CameraDevice;)V") \
  1869. CALLBACK (cameraDeviceStateDisconnectedCallback, "cameraDeviceStateDisconnected", "(JLandroid/hardware/camera2/CameraDevice;)V") \
  1870. CALLBACK (cameraDeviceStateErrorCallback, "cameraDeviceStateError", "(JLandroid/hardware/camera2/CameraDevice;I)V") \
  1871. CALLBACK (cameraDeviceStateOpenedCallback, "cameraDeviceStateOpened", "(JLandroid/hardware/camera2/CameraDevice;)V")
  1872. DECLARE_JNI_CLASS_WITH_MIN_SDK (CameraDeviceStateCallback, "com/rmsl/juce/CameraDeviceStateCallback", 21)
  1873. #undef JNI_CLASS_MEMBERS
  1874. LocalRef<jobject> createCameraStateCallbackObject()
  1875. {
  1876. return LocalRef<jobject> (getEnv()->NewObject (CameraDeviceStateCallback,
  1877. CameraDeviceStateCallback.constructor,
  1878. reinterpret_cast<jlong> (this)));
  1879. }
  1880. //==============================================================================
  1881. void cameraDeviceStateClosed()
  1882. {
  1883. JUCE_CAMERA_LOG ("cameraDeviceStateClosed()");
  1884. closedEvent.signal();
  1885. }
  1886. void cameraDeviceStateDisconnected()
  1887. {
  1888. JUCE_CAMERA_LOG ("cameraDeviceStateDisconnected()");
  1889. if (pendingOpen.compareAndSetBool (0, 1))
  1890. {
  1891. openError = "Device disconnected";
  1892. notifyOpenResult();
  1893. }
  1894. MessageManager::callAsync ([this]() { close(); });
  1895. }
  1896. void cameraDeviceStateError (int errorCode)
  1897. {
  1898. String error = cameraErrorCodeToString (errorCode);
  1899. JUCE_CAMERA_LOG ("cameraDeviceStateError(), error: " + error);
  1900. if (pendingOpen.compareAndSetBool (0, 1))
  1901. {
  1902. openError = error;
  1903. notifyOpenResult();
  1904. }
  1905. fatalErrorOccurred.set (1);
  1906. MessageManager::callAsync ([this, error]()
  1907. {
  1908. owner.cameraDeviceError (error);
  1909. close();
  1910. });
  1911. }
  1912. void cameraDeviceStateOpened (const LocalRef<jobject>& cameraDeviceToUse)
  1913. {
  1914. JUCE_CAMERA_LOG ("cameraDeviceStateOpened()");
  1915. pendingOpen.set (0);
  1916. cameraDevice = GlobalRef (cameraDeviceToUse);
  1917. notifyOpenResult();
  1918. }
  1919. void notifyOpenResult()
  1920. {
  1921. MessageManager::callAsync ([this]() { owner.cameraOpenFinished (openError); });
  1922. }
  1923. //==============================================================================
  1924. static void JNICALL cameraDeviceStateClosedCallback (JNIEnv*, jobject, jlong host, jobject)
  1925. {
  1926. if (auto* myself = reinterpret_cast<ScopedCameraDevice*>(host))
  1927. myself->cameraDeviceStateClosed();
  1928. }
  1929. static void JNICALL cameraDeviceStateDisconnectedCallback (JNIEnv*, jobject, jlong host, jobject)
  1930. {
  1931. if (auto* myself = reinterpret_cast<ScopedCameraDevice*>(host))
  1932. myself->cameraDeviceStateDisconnected();
  1933. }
  1934. static void JNICALL cameraDeviceStateErrorCallback (JNIEnv*, jobject, jlong host, jobject, jint error)
  1935. {
  1936. if (auto* myself = reinterpret_cast<ScopedCameraDevice*>(host))
  1937. myself->cameraDeviceStateError (error);
  1938. }
  1939. static void JNICALL cameraDeviceStateOpenedCallback (JNIEnv*, jobject, jlong host, jobject rawCamera)
  1940. {
  1941. if (auto* myself = reinterpret_cast<ScopedCameraDevice*>(host))
  1942. {
  1943. LocalRef<jobject> camera(getEnv()->NewLocalRef(rawCamera));
  1944. myself->cameraDeviceStateOpened (camera);
  1945. }
  1946. }
  1947. };
  1948. //==============================================================================
  1949. struct CaptureSessionModeBase
  1950. {
  1951. virtual ~CaptureSessionModeBase() = default;
  1952. virtual bool isVideoRecordSession() const = 0;
  1953. virtual void triggerStillPictureCapture() = 0;
  1954. };
  1955. //==============================================================================
  1956. template <typename Mode>
  1957. struct CaptureSessionMode : public CaptureSessionModeBase,
  1958. private PreviewDisplay::Listener,
  1959. private ScopedCameraDevice::CaptureSession::ConfiguredCallback
  1960. {
  1961. ~CaptureSessionMode() override
  1962. {
  1963. captureSession.reset();
  1964. previewDisplay.removeListener (this);
  1965. }
  1966. bool isVideoRecordSession() const override
  1967. {
  1968. return Mode::isVideoRecord();
  1969. }
  1970. void triggerStillPictureCapture() override
  1971. {
  1972. if (captureSession == nullptr)
  1973. {
  1974. // The capture session must be ready before taking a still picture.
  1975. // Did you remember to create and show a preview display?
  1976. jassertfalse;
  1977. return;
  1978. }
  1979. crtp().takeStillPicture();
  1980. }
  1981. protected:
  1982. CaptureSessionMode (Pimpl& ownerToUse, ScopedCameraDevice& cameraDeviceToUse,
  1983. GlobalRef& handlerToUse, PreviewDisplay& pd, int cameraSensorOrientationToUse,
  1984. int cameraLensFacingToUse, StreamConfigurationMap& streamConfigurationMapToUse)
  1985. : owner (ownerToUse),
  1986. scopedCameraDevice (cameraDeviceToUse),
  1987. handler (handlerToUse),
  1988. previewDisplay (pd),
  1989. cameraSensorOrientation (cameraSensorOrientationToUse),
  1990. cameraLensFacing (cameraLensFacingToUse),
  1991. streamConfigurationMap (streamConfigurationMapToUse)
  1992. {
  1993. WeakReference<CaptureSessionMode<Mode>> weakRef (this);
  1994. if (weakRef == nullptr)
  1995. return;
  1996. // async so that the object is fully constructed before the callback gets invoked
  1997. MessageManager::callAsync ([this, weakRef]()
  1998. {
  1999. if (weakRef == nullptr)
  2000. return;
  2001. previewDisplay.addListener (this);
  2002. });
  2003. }
  2004. Mode& crtp() { return static_cast<Mode&> (*this); }
  2005. void previewDisplayReady() override
  2006. {
  2007. jassert (previewDisplay.isReady());
  2008. JUCE_CAMERA_LOG ("previewDisplayReady()");
  2009. // close previous capture session first
  2010. captureSession.reset();
  2011. if (scopedCameraDevice.hasErrorOccurred())
  2012. {
  2013. JUCE_CAMERA_LOG ("Device error detected, not recreating a new camera session. The device needs to be reopened.");
  2014. return;
  2015. }
  2016. captureSession.reset (scopedCameraDevice.createCaptureSession (*this, crtp().getCaptureSessionSurfaces(),
  2017. handler, Mode::getTemplate()));
  2018. }
  2019. void previewDisplayAboutToBeDestroyed() override
  2020. {
  2021. JUCE_CAMERA_LOG ("previewDisplayAboutToBeDestroyed()");
  2022. stopPreview();
  2023. }
  2024. void captureSessionConfigured (ScopedCameraDevice::CaptureSession* session) override
  2025. {
  2026. if (session == nullptr)
  2027. {
  2028. owner.cameraDeviceError ("Failed to configure camera session.");
  2029. return;
  2030. }
  2031. jassert (session == captureSession.get());
  2032. startSession();
  2033. }
  2034. void startSession()
  2035. {
  2036. if (! captureSession->start (crtp().getTargetSurfaces(), handler))
  2037. {
  2038. jassertfalse;
  2039. JUCE_CAMERA_LOG ("Could not start capture session");
  2040. }
  2041. crtp().sessionStarted();
  2042. }
  2043. void stopPreview()
  2044. {
  2045. if (captureSession != nullptr)
  2046. {
  2047. auto session = captureSession->getNativeSession();
  2048. auto* env = getEnv();
  2049. env->CallVoidMethod (session, CameraCaptureSession.stopRepeating);
  2050. if (jniCheckHasExceptionOccurredAndClear())
  2051. return;
  2052. env->CallVoidMethod (session, CameraCaptureSession.abortCaptures);
  2053. jniCheckHasExceptionOccurredAndClear();
  2054. }
  2055. }
  2056. Pimpl& owner;
  2057. ScopedCameraDevice& scopedCameraDevice;
  2058. GlobalRef& handler;
  2059. PreviewDisplay& previewDisplay;
  2060. int cameraSensorOrientation;
  2061. int cameraLensFacing;
  2062. StreamConfigurationMap& streamConfigurationMap;
  2063. std::unique_ptr<ScopedCameraDevice::CaptureSession> captureSession;
  2064. JUCE_DECLARE_WEAK_REFERENCEABLE (CaptureSessionMode<Mode>)
  2065. };
  2066. //==============================================================================
  2067. struct CaptureSessionPreviewMode : public CaptureSessionMode<CaptureSessionPreviewMode>
  2068. {
  2069. CaptureSessionPreviewMode (Pimpl& ownerToUse, ScopedCameraDevice& cameraDeviceToUse, GlobalRef& handlerToUse,
  2070. PreviewDisplay& pd, ImageReader& ir, int sensorOrientation,
  2071. int cameraLensFacingToUse, StreamConfigurationMap& streamConfigurationMapToUse)
  2072. : CaptureSessionMode<CaptureSessionPreviewMode> (ownerToUse, cameraDeviceToUse, handlerToUse, pd,
  2073. sensorOrientation, cameraLensFacingToUse, streamConfigurationMapToUse),
  2074. imageReader (ir)
  2075. {
  2076. }
  2077. // Surfaces passed to newly created capture session.
  2078. LocalRef<jobject> getCaptureSessionSurfaces() const
  2079. {
  2080. auto* env = getEnv();
  2081. auto previewSurface = LocalRef<jobject> (previewDisplay.createSurface());
  2082. auto imageSurface = LocalRef<jobject> (imageReader.getSurface());
  2083. auto arrayList = LocalRef<jobject> (env->NewObject (JavaArrayList, JavaArrayList.constructor, 2));
  2084. env->CallBooleanMethod (arrayList, JavaArrayList.add, previewSurface.get());
  2085. env->CallBooleanMethod (arrayList, JavaArrayList.add, imageSurface.get());
  2086. auto supported = streamConfigurationMap.isOutputSupportedForSurface (imageSurface);
  2087. // Output surface is not supported by this device, still image capture will not work!
  2088. jassert (supported);
  2089. return arrayList;
  2090. }
  2091. // Surfaces set as target during capture.
  2092. LocalRef<jobject> getTargetSurfaces() const
  2093. {
  2094. auto* env = getEnv();
  2095. auto previewSurface = LocalRef<jobject> (previewDisplay.createSurface());
  2096. auto arrayList = LocalRef<jobject> (env->NewObject (JavaArrayList, JavaArrayList.constructor, 1));
  2097. env->CallBooleanMethod (arrayList, JavaArrayList.add, previewSurface.get());
  2098. return arrayList;
  2099. }
  2100. static int getTemplate()
  2101. {
  2102. static constexpr int templatePreview = 1;
  2103. return templatePreview;
  2104. }
  2105. static bool isVideoRecord() { return false; }
  2106. void sessionStarted() {}
  2107. void takeStillPicture()
  2108. {
  2109. imageReader.resetNotificationFlag();
  2110. captureSession->takeStillPicture (imageReader.getSurface());
  2111. }
  2112. private:
  2113. ImageReader& imageReader;
  2114. };
  2115. //==============================================================================
  2116. struct CaptureSessionVideoRecordingMode : public CaptureSessionMode<CaptureSessionVideoRecordingMode>
  2117. {
  2118. CaptureSessionVideoRecordingMode (Pimpl& ownerToUse, ScopedCameraDevice& cameraDeviceToUse, GlobalRef& handlerToUse,
  2119. PreviewDisplay& pd, MediaRecorder& mr, int sensorOrientation,
  2120. int cameraLensFacingToUse, StreamConfigurationMap& streamConfigurationMapToUse)
  2121. : CaptureSessionMode<CaptureSessionVideoRecordingMode> (ownerToUse, cameraDeviceToUse, handlerToUse, pd,
  2122. sensorOrientation, cameraLensFacingToUse, streamConfigurationMapToUse),
  2123. mediaRecorder (mr)
  2124. {
  2125. }
  2126. ~CaptureSessionVideoRecordingMode()
  2127. {
  2128. // We need to explicitly stop the preview before stopping the media recorder,
  2129. // because legacy devices can't handle recording stop before stopping the preview.
  2130. stopPreview();
  2131. mediaRecorder.stop();
  2132. }
  2133. // Surfaces passed to newly created capture session.
  2134. LocalRef<jobject> getCaptureSessionSurfaces() const
  2135. {
  2136. auto* env = getEnv();
  2137. auto previewSurface = LocalRef<jobject> (previewDisplay.createSurface());
  2138. auto mediaRecorderSurface = LocalRef<jobject> (mediaRecorder.getSurface());
  2139. auto arrayList = LocalRef<jobject> (env->NewObject (JavaArrayList, JavaArrayList.constructor, 2));
  2140. env->CallBooleanMethod (arrayList, JavaArrayList.add, previewSurface.get());
  2141. env->CallBooleanMethod (arrayList, JavaArrayList.add, mediaRecorderSurface.get());
  2142. return arrayList;
  2143. }
  2144. // Surfaces set as target during capture.
  2145. LocalRef<jobject> getTargetSurfaces() const
  2146. {
  2147. // Same surfaces used.
  2148. return getCaptureSessionSurfaces();
  2149. }
  2150. static int getTemplate()
  2151. {
  2152. static constexpr int templateRecord = 3;
  2153. return templateRecord;
  2154. }
  2155. static bool isVideoRecord() { return true; }
  2156. void sessionStarted()
  2157. {
  2158. MessageManager::callAsync ([this]() { mediaRecorder.start(); });
  2159. }
  2160. void takeStillPicture()
  2161. {
  2162. // Taking still pictures while recording video is not supported on Android.
  2163. jassertfalse;
  2164. }
  2165. private:
  2166. MediaRecorder& mediaRecorder;
  2167. };
  2168. //==============================================================================
  2169. class DeviceOrientationChangeListener : private Timer
  2170. {
  2171. public:
  2172. DeviceOrientationChangeListener (PreviewDisplay& pd)
  2173. : previewDisplay (pd),
  2174. orientationEventListener (createOrientationEventListener()),
  2175. canDetectChange (getEnv()->CallBooleanMethod (orientationEventListener,
  2176. OrientationEventListener.canDetectOrientation) != 0),
  2177. deviceOrientation (Desktop::getInstance().getCurrentOrientation()),
  2178. lastKnownScreenOrientation (deviceOrientation)
  2179. {
  2180. setEnabled (true);
  2181. }
  2182. ~DeviceOrientationChangeListener() override
  2183. {
  2184. setEnabled (false);
  2185. }
  2186. void setEnabled (bool shouldBeEnabled)
  2187. {
  2188. if (shouldBeEnabled && ! canDetectChange)
  2189. {
  2190. // This device does not support orientation listening, photos may have wrong orientation!
  2191. jassertfalse;
  2192. return;
  2193. }
  2194. if (shouldBeEnabled)
  2195. getEnv()->CallVoidMethod (orientationEventListener, OrientationEventListener.enable);
  2196. else
  2197. getEnv()->CallVoidMethod (orientationEventListener, OrientationEventListener.disable);
  2198. }
  2199. bool isSupported() const noexcept { return canDetectChange; }
  2200. Desktop::DisplayOrientation getDeviceOrientation() const noexcept
  2201. {
  2202. return deviceOrientation;
  2203. }
  2204. private:
  2205. PreviewDisplay& previewDisplay;
  2206. GlobalRef orientationEventListener;
  2207. static constexpr jint sensorDelayUI = 2;
  2208. bool canDetectChange;
  2209. Desktop::DisplayOrientation deviceOrientation;
  2210. Desktop::DisplayOrientation lastKnownScreenOrientation;
  2211. int numChecksForOrientationChange = 10;
  2212. //==============================================================================
  2213. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  2214. METHOD (canDetectOrientation, "canDetectOrientation", "()Z") \
  2215. METHOD (constructor, "<init>", "(JLandroid/content/Context;I)V") \
  2216. METHOD (disable, "disable", "()V") \
  2217. METHOD (enable, "enable", "()V") \
  2218. CALLBACK (deviceOrientationChanged, "deviceOrientationChanged", "(JI)V")
  2219. DECLARE_JNI_CLASS_WITH_MIN_SDK (OrientationEventListener, "com/rmsl/juce/JuceOrientationEventListener", 21)
  2220. #undef JNI_CLASS_MEMBERS
  2221. LocalRef<jobject> createOrientationEventListener()
  2222. {
  2223. return LocalRef<jobject> (getEnv()->NewObject (OrientationEventListener,
  2224. OrientationEventListener.constructor,
  2225. reinterpret_cast<jlong> (this),
  2226. getAppContext().get(),
  2227. sensorDelayUI));
  2228. }
  2229. //==============================================================================
  2230. void orientationChanged (int orientation)
  2231. {
  2232. jassert (orientation < 360);
  2233. // -1 == unknown
  2234. if (orientation < 0)
  2235. return;
  2236. auto oldOrientation = deviceOrientation;
  2237. // NB: this assumes natural position to be portrait always, but some devices may be landscape...
  2238. if (orientation > (360 - 45) || orientation < 45)
  2239. deviceOrientation = Desktop::upright;
  2240. else if (orientation < 135)
  2241. deviceOrientation = Desktop::rotatedClockwise;
  2242. else if (orientation < 225)
  2243. deviceOrientation = Desktop::upsideDown;
  2244. else
  2245. deviceOrientation = Desktop::rotatedAntiClockwise;
  2246. if (oldOrientation != deviceOrientation)
  2247. {
  2248. lastKnownScreenOrientation = Desktop::getInstance().getCurrentOrientation();
  2249. // Need to update preview transform, but screen orientation will change slightly
  2250. // later than sensor orientation.
  2251. startTimer (500);
  2252. }
  2253. }
  2254. void timerCallback() override
  2255. {
  2256. auto currentOrientation = Desktop::getInstance().getCurrentOrientation();
  2257. if (lastKnownScreenOrientation != currentOrientation)
  2258. {
  2259. lastKnownScreenOrientation = currentOrientation;
  2260. stopTimer();
  2261. numChecksForOrientationChange = 10;
  2262. previewDisplay.updateSurfaceTransform();
  2263. return;
  2264. }
  2265. if (--numChecksForOrientationChange == 0)
  2266. {
  2267. stopTimer();
  2268. numChecksForOrientationChange = 10;
  2269. }
  2270. }
  2271. static void deviceOrientationChanged (JNIEnv*, jobject /*obj*/, jlong host, jint orientation)
  2272. {
  2273. if (auto* myself = reinterpret_cast<DeviceOrientationChangeListener*> (host))
  2274. myself->orientationChanged (orientation);
  2275. }
  2276. };
  2277. //==============================================================================
  2278. CameraDevice& owner;
  2279. int minWidth, minHeight, maxWidth, maxHeight;
  2280. String cameraId;
  2281. InternalOpenCameraResultCallback cameraOpenCallback;
  2282. GlobalRef activityLifeListener;
  2283. GlobalRef cameraManager;
  2284. GlobalRef cameraCharacteristics;
  2285. GlobalRef handlerThread;
  2286. GlobalRef handler;
  2287. StreamConfigurationMap streamConfigurationMap;
  2288. PreviewDisplay previewDisplay;
  2289. DeviceOrientationChangeListener deviceOrientationChangeListener;
  2290. std::unique_ptr<ImageReader> imageReader;
  2291. std::unique_ptr<MediaRecorder> mediaRecorder;
  2292. std::unique_ptr<CaptureSessionModeBase> currentCaptureSessionMode;
  2293. std::unique_ptr<ScopedCameraDevice> scopedCameraDevice;
  2294. CriticalSection listenerLock;
  2295. ListenerList<Listener> listeners;
  2296. std::function<void(const Image&)> pictureTakenCallback;
  2297. Time firstRecordedFrameTimeMs;
  2298. bool notifiedOfCameraOpening = false;
  2299. bool appWasPaused = false;
  2300. //==============================================================================
  2301. int getCameraSensorOrientation() const
  2302. {
  2303. return getCameraCharacteristicsIntegerKeyValue (CameraCharacteristics.SENSOR_ORIENTATION);
  2304. }
  2305. int getAutoFocusModeToUse() const
  2306. {
  2307. auto supportedModes = getSupportedAutoFocusModes();
  2308. enum
  2309. {
  2310. CONTROL_AF_MODE_OFF = 0,
  2311. CONTROL_AF_MODE_AUTO = 1,
  2312. CONTROL_AF_MODE_CONTINUOUS_PICTURE = 4
  2313. };
  2314. if (supportedModes.contains (CONTROL_AF_MODE_CONTINUOUS_PICTURE))
  2315. return CONTROL_AF_MODE_CONTINUOUS_PICTURE;
  2316. if (supportedModes.contains (CONTROL_AF_MODE_AUTO))
  2317. return CONTROL_AF_MODE_AUTO;
  2318. return CONTROL_AF_MODE_OFF;
  2319. }
  2320. Array<int> getSupportedAutoFocusModes() const
  2321. {
  2322. auto* env = getEnv();
  2323. auto jKey = LocalRef<jobject> (env->GetStaticObjectField (CameraCharacteristics, CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES));
  2324. auto supportedModes = LocalRef<jintArray> ((jintArray) env->CallObjectMethod (cameraCharacteristics,
  2325. CameraCharacteristics.get,
  2326. jKey.get()));
  2327. return jintArrayToJuceArray (supportedModes);
  2328. }
  2329. static Array<int> jintArrayToJuceArray (const LocalRef<jintArray>& jArray)
  2330. {
  2331. auto* env = getEnv();
  2332. auto* jArrayElems = env->GetIntArrayElements (jArray, nullptr);
  2333. auto numElems = env->GetArrayLength (jArray);
  2334. Array<int> juceArray;
  2335. for (int s = 0; s < numElems; ++s)
  2336. juceArray.add (jArrayElems[s]);
  2337. env->ReleaseIntArrayElements (jArray, jArrayElems, 0);
  2338. return juceArray;
  2339. }
  2340. int getCameraCharacteristicsIntegerKeyValue (jfieldID key) const
  2341. {
  2342. auto* env = getEnv();
  2343. auto jKey = LocalRef<jobject> (env->GetStaticObjectField (CameraCharacteristics, key));
  2344. auto jValue = LocalRef<jobject> (env->CallObjectMethod (cameraCharacteristics,
  2345. CameraCharacteristics.get,
  2346. jKey.get()));
  2347. return env->CallIntMethod (jValue, JavaInteger.intValue);
  2348. }
  2349. int getCameraLensFacing() const
  2350. {
  2351. return getCameraCharacteristicsIntegerKeyValue (CameraCharacteristics.LENS_FACING);
  2352. }
  2353. //==============================================================================
  2354. void cameraOpenFinished (const String& error)
  2355. {
  2356. JUCE_CAMERA_LOG ("cameraOpenFinished(), error = " + error);
  2357. if (error.isEmpty())
  2358. {
  2359. setupStillImageSize();
  2360. startPreviewMode (*imageReader);
  2361. }
  2362. // Do not notify about camera being reopened on app resume.
  2363. if (! notifiedOfCameraOpening)
  2364. {
  2365. notifiedOfCameraOpening = true;
  2366. invokeCameraOpenCallback (error);
  2367. }
  2368. }
  2369. void cameraDeviceError (const String& error)
  2370. {
  2371. if (owner.onErrorOccurred != nullptr)
  2372. owner.onErrorOccurred (error);
  2373. }
  2374. void invokeCameraOpenCallback (const String& error)
  2375. {
  2376. JUCE_CAMERA_LOG ("invokeCameraOpenCallback(), error = " + error);
  2377. if (cameraOpenCallback != nullptr)
  2378. cameraOpenCallback (cameraId, error);
  2379. }
  2380. //==============================================================================
  2381. void callListeners (const Image& image)
  2382. {
  2383. const ScopedLock sl (listenerLock);
  2384. listeners.call ([=] (Listener& l) { l.imageReceived (image); });
  2385. }
  2386. void notifyPictureTaken (const Image& image)
  2387. {
  2388. JUCE_CAMERA_LOG ("notifyPictureTaken()");
  2389. if (pictureTakenCallback != nullptr)
  2390. pictureTakenCallback (image);
  2391. }
  2392. void triggerStillPictureCapture()
  2393. {
  2394. currentCaptureSessionMode->triggerStillPictureCapture();
  2395. }
  2396. //==============================================================================
  2397. void setupStillImageSize()
  2398. {
  2399. imageReader.reset();
  2400. auto imageSize = chooseBestSize (minWidth, minHeight, maxWidth, maxHeight,
  2401. streamConfigurationMap.getSupportedStillImageOutputSizes());
  2402. imageReader.reset (new ImageReader (*this, handler, imageSize.getWidth(), imageSize.getHeight(),
  2403. getCameraSensorOrientation()));
  2404. }
  2405. static Rectangle<int> chooseBestSize (int minWidth, int minHeight, int maxWidth, int maxHeight,
  2406. Array<Rectangle<int>> supportedSizes)
  2407. {
  2408. Rectangle<int> result;
  2409. for (auto& size : supportedSizes)
  2410. {
  2411. auto width = size.getWidth();
  2412. auto height = size.getHeight();
  2413. if (width < minWidth || width > maxWidth || height < minHeight || height > maxHeight)
  2414. continue;
  2415. if (size.contains (result))
  2416. result = size;
  2417. }
  2418. // None of the supported sizes matches required width & height limitations, picking
  2419. // the first one available...
  2420. jassert (! result.isEmpty());
  2421. if (result.isEmpty())
  2422. result = supportedSizes[0];
  2423. return result;
  2424. }
  2425. //==============================================================================
  2426. void startPreviewMode (ImageReader& ir)
  2427. {
  2428. if (currentCaptureSessionMode != nullptr && ! currentCaptureSessionMode->isVideoRecordSession())
  2429. return;
  2430. // previous mode has to be stopped first
  2431. jassert (currentCaptureSessionMode.get() == nullptr);
  2432. if (scopedCameraDevice == nullptr || ! scopedCameraDevice->openedOk())
  2433. return;
  2434. currentCaptureSessionMode.reset (new CaptureSessionPreviewMode (*this, *scopedCameraDevice, handler,
  2435. previewDisplay, ir,
  2436. getCameraSensorOrientation(),
  2437. getCameraLensFacing(),
  2438. streamConfigurationMap));
  2439. }
  2440. void startVideoRecordingMode (MediaRecorder& mr)
  2441. {
  2442. if (currentCaptureSessionMode != nullptr && currentCaptureSessionMode->isVideoRecordSession())
  2443. return;
  2444. // previous mode has to be stopped first
  2445. jassert (currentCaptureSessionMode.get() == nullptr);
  2446. jassert (scopedCameraDevice != nullptr && scopedCameraDevice->openedOk());
  2447. if (scopedCameraDevice == nullptr || ! scopedCameraDevice->openedOk())
  2448. return;
  2449. currentCaptureSessionMode.reset (new CaptureSessionVideoRecordingMode (*this, *scopedCameraDevice, handler,
  2450. previewDisplay, mr,
  2451. getCameraSensorOrientation(),
  2452. getCameraLensFacing(),
  2453. streamConfigurationMap));
  2454. }
  2455. //==============================================================================
  2456. void onActivityPaused (jobject) override
  2457. {
  2458. JUCE_CAMERA_LOG ("appPaused, closing camera...");
  2459. appWasPaused = true;
  2460. deviceOrientationChangeListener.setEnabled (false);
  2461. // We need to restart the whole session mode when the app gets resumed.
  2462. currentCaptureSessionMode.reset();
  2463. if (scopedCameraDevice != nullptr)
  2464. scopedCameraDevice->close();
  2465. stopBackgroundThread();
  2466. }
  2467. void onActivityResumed (jobject) override
  2468. {
  2469. // Only care about resumed event when paused event was called first.
  2470. if (! appWasPaused)
  2471. return;
  2472. JUCE_CAMERA_LOG ("appResumed, opening camera...");
  2473. deviceOrientationChangeListener.setEnabled (true);
  2474. startBackgroundThread();
  2475. if (scopedCameraDevice != nullptr)
  2476. scopedCameraDevice->open();
  2477. }
  2478. void startBackgroundThread()
  2479. {
  2480. auto* env = getEnv();
  2481. handlerThread = GlobalRef (LocalRef<jobject> (env->NewObject (AndroidHandlerThread,
  2482. AndroidHandlerThread.constructor,
  2483. javaString ("JuceCameraDeviceBackgroundThread").get())));
  2484. // handler thread has to be started before its looper can be fetched
  2485. env->CallVoidMethod (handlerThread, AndroidHandlerThread.start);
  2486. handler = GlobalRef (LocalRef<jobject> (env->NewObject (AndroidHandler,
  2487. AndroidHandler.constructorWithLooper,
  2488. env->CallObjectMethod (handlerThread, AndroidHandlerThread.getLooper))));
  2489. }
  2490. void stopBackgroundThread()
  2491. {
  2492. auto* env = getEnv();
  2493. auto quitSafelyMethod = env->GetMethodID(AndroidHandlerThread, "quitSafely", "()Z");
  2494. // this code will only run on SDK >= 21
  2495. jassert(quitSafelyMethod != nullptr);
  2496. env->CallBooleanMethod (handlerThread, quitSafelyMethod);
  2497. env->CallVoidMethod (handlerThread, AndroidHandlerThread.join);
  2498. jniCheckHasExceptionOccurredAndClear();
  2499. handlerThread.clear();
  2500. handler.clear();
  2501. }
  2502. friend struct CameraDevice::ViewerComponent;
  2503. JUCE_DECLARE_NON_COPYABLE (Pimpl)
  2504. };
  2505. //==============================================================================
  2506. struct CameraDevice::ViewerComponent : public Component,
  2507. private ComponentMovementWatcher
  2508. {
  2509. ViewerComponent (CameraDevice& device) : ComponentMovementWatcher (this)
  2510. {
  2511. auto previewSize = device.pimpl->streamConfigurationMap.getDefaultPreviewSize();
  2512. targetAspectRatio = previewSize.getWidth() / (float) previewSize.getHeight();
  2513. if (isOrientationLandscape())
  2514. setBounds (previewSize);
  2515. else
  2516. setBounds (0, 0, previewSize.getHeight(), previewSize.getWidth());
  2517. addAndMakeVisible (viewerComponent);
  2518. viewerComponent.setView (device.pimpl->previewDisplay.getNativeView());
  2519. }
  2520. private:
  2521. AndroidViewComponent viewerComponent;
  2522. float targetAspectRatio = 1.0f;
  2523. void componentMovedOrResized (bool, bool) override
  2524. {
  2525. auto b = getLocalBounds();
  2526. auto targetWidth = b.getWidth();
  2527. auto targetHeight = b.getHeight();
  2528. if (isOrientationLandscape())
  2529. {
  2530. auto currentAspectRatio = b.getWidth() / (float) b.getHeight();
  2531. if (currentAspectRatio > targetAspectRatio)
  2532. targetWidth = static_cast<int> (targetWidth * targetAspectRatio / currentAspectRatio);
  2533. else
  2534. targetHeight = static_cast<int> (targetHeight * currentAspectRatio / targetAspectRatio);
  2535. }
  2536. else
  2537. {
  2538. auto currentAspectRatio = b.getHeight() / (float) b.getWidth();
  2539. if (currentAspectRatio > targetAspectRatio)
  2540. targetHeight = static_cast<int> (targetHeight * targetAspectRatio / currentAspectRatio);
  2541. else
  2542. targetWidth = static_cast<int> (targetWidth * currentAspectRatio / targetAspectRatio);
  2543. }
  2544. viewerComponent.setBounds (Rectangle<int> (0, 0, targetWidth, targetHeight).withCentre (b.getCentre()));
  2545. }
  2546. bool isOrientationLandscape() const
  2547. {
  2548. auto o = Desktop::getInstance().getCurrentOrientation();
  2549. return o == Desktop::rotatedClockwise || o == Desktop::rotatedAntiClockwise;
  2550. }
  2551. void componentPeerChanged() override {}
  2552. void componentVisibilityChanged() override {}
  2553. JUCE_DECLARE_NON_COPYABLE (ViewerComponent)
  2554. };
  2555. String CameraDevice::getFileExtension()
  2556. {
  2557. return ".mp4";
  2558. }
  2559. //==============================================================================
  2560. CameraDevice::Pimpl::ScopedCameraDevice::CaptureSession::StillPictureTaker::CameraCaptureSessionCaptureCallback_Class CameraDevice::Pimpl::ScopedCameraDevice::CaptureSession::StillPictureTaker::CameraCaptureSessionCaptureCallback;
  2561. CameraDevice::Pimpl::ScopedCameraDevice::CameraDeviceStateCallback_Class CameraDevice::Pimpl::ScopedCameraDevice::CameraDeviceStateCallback;
  2562. CameraDevice::Pimpl::ScopedCameraDevice::CaptureSession::CameraCaptureSessionStateCallback_Class CameraDevice::Pimpl::ScopedCameraDevice::CaptureSession::CameraCaptureSessionStateCallback;
  2563. CameraDevice::Pimpl::DeviceOrientationChangeListener::OrientationEventListener_Class CameraDevice::Pimpl::DeviceOrientationChangeListener::OrientationEventListener;