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.

3289 lines
146KB

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