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    try {
70        const { state } = await navigator.permissions.query({ name: query });
71        switch (state) {
72            case 'prompt':
73                return {
74                    status: PermissionStatus.UNDETERMINED,
75                    expires: 'never',
76                    canAskAgain: true,
77                    granted: false,
78                };
79            case 'granted':
80                return {
81                    status: PermissionStatus.GRANTED,
82                    expires: 'never',
83                    canAskAgain: true,
84                    granted: true,
85                };
86            case 'denied':
87                return {
88                    status: PermissionStatus.DENIED,
89                    expires: 'never',
90                    canAskAgain: true,
91                    granted: false,
92                };
93        }
94    }
95    catch (e) {
96        // Firefox doesn't support querying for the camera permission, so return undetermined status
97        if (e instanceof TypeError) {
98            return {
99                status: PermissionStatus.UNDETERMINED,
100                expires: 'never',
101                canAskAgain: true,
102                granted: false,
103            };
104        }
105        throw e;
106    }
107}
108export default {
109    get name() {
110        return 'ExponentCameraManager';
111    },
112    get Type() {
113        return {
114            back: 'back',
115            front: 'front',
116        };
117    },
118    get FlashMode() {
119        return {
120            on: 'on',
121            off: 'off',
122            auto: 'auto',
123            torch: 'torch',
124        };
125    },
126    get AutoFocus() {
127        return {
128            on: 'on',
129            off: 'off',
130            auto: 'auto',
131            singleShot: 'singleShot',
132        };
133    },
134    get WhiteBalance() {
135        return {
136            auto: 'auto',
137            continuous: 'continuous',
138            manual: 'manual',
139        };
140    },
141    get VideoQuality() {
142        return {};
143    },
144    get VideoStabilization() {
145        return {};
146    },
147    async isAvailableAsync() {
148        return canGetUserMedia();
149    },
150    async takePicture(options, camera) {
151        return await camera.takePicture(options);
152    },
153    async pausePreview(camera) {
154        await camera.pausePreview();
155    },
156    async resumePreview(camera) {
157        return await camera.resumePreview();
158    },
159    async getAvailableCameraTypesAsync() {
160        if (!canGetUserMedia() || !navigator.mediaDevices.enumerateDevices)
161            return [];
162        const devices = await navigator.mediaDevices.enumerateDevices();
163        const types = await Promise.all([
164            (await isFrontCameraAvailableAsync(devices)) && CameraType.front,
165            (await isBackCameraAvailableAsync()) && CameraType.back,
166        ]);
167        return types.filter(Boolean);
168    },
169    async getAvailablePictureSizes(ratio, camera) {
170        return await camera.getAvailablePictureSizes(ratio);
171    },
172    /* async getSupportedRatios(camera: ExponentCameraRef): Promise<string[]> {
173      // TODO: Support on web
174    },
175    async record(
176      options?: CameraRecordingOptions,
177      camera: ExponentCameraRef
178    ): Promise<{ uri: string }> {
179      // TODO: Support on web
180    },
181    async stopRecording(camera: ExponentCameraRef): Promise<void> {
182      // TODO: Support on web
183    }, */
184    async getPermissionsAsync() {
185        return handlePermissionsQueryAsync('camera');
186    },
187    async requestPermissionsAsync() {
188        return handleRequestPermissionsAsync();
189    },
190    async getCameraPermissionsAsync() {
191        return handlePermissionsQueryAsync('camera');
192    },
193    async requestCameraPermissionsAsync() {
194        return handleRequestPermissionsAsync();
195    },
196    async getMicrophonePermissionsAsync() {
197        return handlePermissionsQueryAsync('microphone');
198    },
199    async requestMicrophonePermissionsAsync() {
200        try {
201            await getUserMedia({
202                audio: true,
203            });
204            return {
205                status: PermissionStatus.GRANTED,
206                expires: 'never',
207                canAskAgain: true,
208                granted: true,
209            };
210        }
211        catch ({ message }) {
212            return handleGetUserMediaError({ message });
213        }
214    },
215};
216//# sourceMappingURL=ExponentCameraManager.web.js.map