1import { UnavailabilityError } from 'expo-modules-core'; 2import { CameraType, PermissionStatus, } from './Camera.types'; 3import { canGetUserMedia, isBackCameraAvailableAsync, isFrontCameraAvailableAsync, } from './WebUserMediaManager'; 4function getUserMedia(constraints) { 5 if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { 6 return navigator.mediaDevices.getUserMedia(constraints); 7 } 8 // Some browsers partially implement mediaDevices. We can't just assign an object 9 // with getUserMedia as it would overwrite existing properties. 10 // Here, we will just add the getUserMedia property if it's missing. 11 // First get ahold of the legacy getUserMedia, if present 12 const getUserMedia = 13 // TODO: this method is deprecated, migrate to https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia 14 navigator.getUserMedia || 15 navigator.webkitGetUserMedia || 16 navigator.mozGetUserMedia || 17 function () { 18 const error = new Error('Permission unimplemented'); 19 error.code = 0; 20 error.name = 'NotAllowedError'; 21 throw error; 22 }; 23 return new Promise((resolve, reject) => { 24 getUserMedia.call(navigator, constraints, resolve, reject); 25 }); 26} 27function handleGetUserMediaError({ message }) { 28 // name: NotAllowedError 29 // code: 0 30 if (message === 'Permission dismissed') { 31 return { 32 status: PermissionStatus.UNDETERMINED, 33 expires: 'never', 34 canAskAgain: true, 35 granted: false, 36 }; 37 } 38 else { 39 // TODO: Bacon: [OSX] The system could deny access to chrome. 40 // TODO: Bacon: add: { status: 'unimplemented' } 41 return { 42 status: PermissionStatus.DENIED, 43 expires: 'never', 44 canAskAgain: true, 45 granted: false, 46 }; 47 } 48} 49async function handleRequestPermissionsAsync() { 50 try { 51 await getUserMedia({ 52 video: true, 53 }); 54 return { 55 status: PermissionStatus.GRANTED, 56 expires: 'never', 57 canAskAgain: true, 58 granted: true, 59 }; 60 } 61 catch ({ message }) { 62 return handleGetUserMediaError({ message }); 63 } 64} 65async function handlePermissionsQueryAsync(query) { 66 if (!navigator?.permissions?.query) { 67 throw new UnavailabilityError('expo-camera', 'navigator.permissions API is not available'); 68 } 69 const { state } = await navigator.permissions.query({ name: query }); 70 switch (state) { 71 case 'prompt': 72 return { 73 status: PermissionStatus.UNDETERMINED, 74 expires: 'never', 75 canAskAgain: true, 76 granted: false, 77 }; 78 case 'granted': 79 return { 80 status: PermissionStatus.GRANTED, 81 expires: 'never', 82 canAskAgain: true, 83 granted: true, 84 }; 85 case 'denied': 86 return { 87 status: PermissionStatus.DENIED, 88 expires: 'never', 89 canAskAgain: true, 90 granted: false, 91 }; 92 } 93} 94export default { 95 get name() { 96 return 'ExponentCameraManager'; 97 }, 98 get Type() { 99 return { 100 back: 'back', 101 front: 'front', 102 }; 103 }, 104 get FlashMode() { 105 return { 106 on: 'on', 107 off: 'off', 108 auto: 'auto', 109 torch: 'torch', 110 }; 111 }, 112 get AutoFocus() { 113 return { 114 on: 'on', 115 off: 'off', 116 auto: 'auto', 117 singleShot: 'singleShot', 118 }; 119 }, 120 get WhiteBalance() { 121 return { 122 auto: 'auto', 123 continuous: 'continuous', 124 manual: 'manual', 125 }; 126 }, 127 get VideoQuality() { 128 return {}; 129 }, 130 get VideoStabilization() { 131 return {}; 132 }, 133 async isAvailableAsync() { 134 return canGetUserMedia(); 135 }, 136 async takePicture(options, camera) { 137 return await camera.takePicture(options); 138 }, 139 async pausePreview(camera) { 140 await camera.pausePreview(); 141 }, 142 async resumePreview(camera) { 143 return await camera.resumePreview(); 144 }, 145 async getAvailableCameraTypesAsync() { 146 if (!canGetUserMedia() || !navigator.mediaDevices.enumerateDevices) 147 return []; 148 const devices = await navigator.mediaDevices.enumerateDevices(); 149 const types = await Promise.all([ 150 (await isFrontCameraAvailableAsync(devices)) && CameraType.front, 151 (await isBackCameraAvailableAsync()) && CameraType.back, 152 ]); 153 return types.filter(Boolean); 154 }, 155 async getAvailablePictureSizes(ratio, camera) { 156 return await camera.getAvailablePictureSizes(ratio); 157 }, 158 /* async getSupportedRatios(camera: ExponentCameraRef): Promise<string[]> { 159 // TODO: Support on web 160 }, 161 async record( 162 options?: CameraRecordingOptions, 163 camera: ExponentCameraRef 164 ): Promise<{ uri: string }> { 165 // TODO: Support on web 166 }, 167 async stopRecording(camera: ExponentCameraRef): Promise<void> { 168 // TODO: Support on web 169 }, */ 170 async getPermissionsAsync() { 171 return handlePermissionsQueryAsync('camera'); 172 }, 173 async requestPermissionsAsync() { 174 return handleRequestPermissionsAsync(); 175 }, 176 async getCameraPermissionsAsync() { 177 return handlePermissionsQueryAsync('camera'); 178 }, 179 async requestCameraPermissionsAsync() { 180 return handleRequestPermissionsAsync(); 181 }, 182 async getMicrophonePermissionsAsync() { 183 return handlePermissionsQueryAsync('microphone'); 184 }, 185 async requestMicrophonePermissionsAsync() { 186 try { 187 await getUserMedia({ 188 audio: true, 189 }); 190 return { 191 status: PermissionStatus.GRANTED, 192 expires: 'never', 193 canAskAgain: true, 194 granted: true, 195 }; 196 } 197 catch ({ message }) { 198 return handleGetUserMediaError({ message }); 199 } 200 }, 201}; 202//# sourceMappingURL=ExponentCameraManager.web.js.map