Skip to content

Commit de9e1db

Browse files
authored
VideoTexture WebCam Permission Check (#450)
* add permission check
1 parent 902290e commit de9e1db

File tree

1 file changed

+46
-27
lines changed

1 file changed

+46
-27
lines changed

Modules/@babylonjs/react-native/EngineHook.ts

+46-27
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useEffect, useState } from 'react';
22
import { Platform } from 'react-native';
33
import { PERMISSIONS, check, request } from 'react-native-permissions';
4-
import { Engine, WebXRSessionManager, WebXRExperienceHelper, Color4, Tools } from '@babylonjs/core';
4+
import { Engine, WebXRSessionManager, WebXRExperienceHelper, Color4, Tools, VideoTexture } from '@babylonjs/core';
55
import { ReactNativeEngine } from './ReactNativeEngine';
66

77
import * as base64 from 'base-64';
@@ -21,46 +21,65 @@ class DOMException {
2121
get name(): string { return DOMError[this.error]; }
2222
}
2323

24+
// Requests the camera permission and throws if the permission could not be granted
25+
async function requestCameraPermissionAsync() : Promise<void> {
26+
const cameraPermission = Platform.select({
27+
android: PERMISSIONS.ANDROID.CAMERA,
28+
ios: PERMISSIONS.IOS.CAMERA,
29+
});
30+
31+
// Only Android, iOS and Windows are supported.
32+
if (cameraPermission === undefined) {
33+
throw new DOMException(DOMError.NotSupportedError);
34+
}
35+
36+
// If the permission has not been granted yet, but also not been blocked, then request permission.
37+
let permissionStatus = await check(cameraPermission);
38+
if (permissionStatus == "denied")
39+
{
40+
permissionStatus = await request(cameraPermission);
41+
}
42+
43+
// If the permission has still not been granted, then throw an appropriate exception, otherwise continue with the actual XR session initialization.
44+
switch(permissionStatus) {
45+
case "unavailable":
46+
throw new DOMException(DOMError.NotSupportedError);
47+
case "denied":
48+
case "blocked":
49+
throw new DOMException(DOMError.SecurityError);
50+
case "granted":
51+
return;
52+
}
53+
}
54+
2455
// Override the WebXRSessionManager.initializeSessionAsync to insert a camera permissions request. It would be cleaner to do this directly in the native XR implementation, but there are a couple problems with that:
2556
// 1. React Native does not provide a way to hook into the permissions request result (at least on Android).
2657
// 2. If it is done on the native side, then we need one implementation per platform.
2758
{
28-
const originalInitializeSessionAsync: (...args: any[]) => Promise<any> = WebXRSessionManager.prototype.initializeSessionAsync;
29-
WebXRSessionManager.prototype.initializeSessionAsync = async function (...args: any[]): Promise<any> {
59+
const originalInitializeSessionAsync = WebXRSessionManager.prototype.initializeSessionAsync;
60+
WebXRSessionManager.prototype.initializeSessionAsync = async function (...args: Parameters<typeof originalInitializeSessionAsync>): ReturnType<typeof originalInitializeSessionAsync> {
3061
if (Platform.OS === "windows")
3162
{
3263
// Launching into immersive mode on Windows HMDs doesn't require a runtime permission check.
3364
// The Spatial Perception capability should be enabled in the project's Package.appxmanifest.
3465
return originalInitializeSessionAsync.apply(this, args);
3566
}
3667

37-
const cameraPermission = Platform.select({
38-
android: PERMISSIONS.ANDROID.CAMERA,
39-
ios: PERMISSIONS.IOS.CAMERA,
40-
});
68+
await requestCameraPermissionAsync();
4169

42-
// Only Android, iOS and Windows are supported.
43-
if (cameraPermission === undefined) {
44-
throw new DOMException(DOMError.NotSupportedError);
45-
}
70+
return originalInitializeSessionAsync.apply(this, args);
71+
}
72+
}
4673

47-
// If the permission has not been granted yet, but also not been blocked, then request permission.
48-
let permissionStatus = await check(cameraPermission);
49-
if (permissionStatus == "denied")
50-
{
51-
permissionStatus = await request(cameraPermission);
52-
}
74+
// Override the VideoTexture.CreateFromWebCamAsync to insert a camera permissions request. It would be cleaner to do this directly in the NativeCamera implementation, but there are a couple problems with that:
75+
// 1. React Native does not provide a way to hook into the permissions request result (at least on Android).
76+
// 2. If it is done on the native side, then we need one implementation per platform.
77+
{
78+
const originalCreateFromWebCamAsync = VideoTexture.CreateFromWebCamAsync;
79+
VideoTexture.CreateFromWebCamAsync = async function (...args: Parameters<typeof originalCreateFromWebCamAsync>): ReturnType<typeof originalCreateFromWebCamAsync> {
80+
await requestCameraPermissionAsync();
5381

54-
// If the permission has still not been granted, then throw an appropriate exception, otherwise continue with the actual XR session initialization.
55-
switch(permissionStatus) {
56-
case "unavailable":
57-
throw new DOMException(DOMError.NotSupportedError);
58-
case "denied":
59-
case "blocked":
60-
throw new DOMException(DOMError.SecurityError);
61-
case "granted":
62-
return originalInitializeSessionAsync.apply(this, args);
63-
}
82+
return originalCreateFromWebCamAsync.apply(this, args);
6483
}
6584
}
6685

0 commit comments

Comments
 (0)