blob: 7b87840a90f82ac72a94ca01613f558fea69e87b [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:html' as html;
import 'dart:ui';
import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:camera_web/src/types/types.dart';
import 'package:flutter/foundation.dart';
/// A utility to fetch and map camera settings.
class CameraSettings {
// A facing mode constraint name.
static const _facingModeKey = "facingMode";
/// The current browser window used to access media devices.
@visibleForTesting
html.Window? window = html.window;
/// Returns a facing mode of the [videoTrack]
/// (null if the facing mode is not available).
String? getFacingModeForVideoTrack(html.MediaStreamTrack videoTrack) {
final mediaDevices = window?.navigator.mediaDevices;
// Throw a not supported exception if the current browser window
// does not support any media devices.
if (mediaDevices == null) {
throw CameraException(
CameraErrorCodes.notSupported,
'The camera is not supported on this device.',
);
}
// Check if the camera facing mode is supported by the current browser.
final supportedConstraints = mediaDevices.getSupportedConstraints();
final facingModeSupported = supportedConstraints[_facingModeKey] ?? false;
// Return null if the facing mode is not supported.
if (!facingModeSupported) {
return null;
}
// Extract the facing mode from the video track settings.
// The property may not be available if it's not supported
// by the browser or not available due to context.
//
// MediaTrackSettings:
// https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings
final videoTrackSettings = videoTrack.getSettings();
final facingMode = videoTrackSettings[_facingModeKey];
if (facingMode == null) {
try {
// If the facing mode does not exist in the video track settings,
// check for the facing mode in the video track capabilities.
//
// MediaTrackCapabilities:
// https://www.w3.org/TR/mediacapture-streams/#dom-mediatrackcapabilities
//
// This may throw a not supported error on Firefox.
final videoTrackCapabilities = videoTrack.getCapabilities();
// A list of facing mode capabilities as
// the camera may support multiple facing modes.
final facingModeCapabilities =
List<String>.from(videoTrackCapabilities[_facingModeKey] ?? []);
if (facingModeCapabilities.isNotEmpty) {
final facingModeCapability = facingModeCapabilities.first;
return facingModeCapability;
} else {
// Return null if there are no facing mode capabilities.
return null;
}
} catch (e) {
switch (e.runtimeType.toString()) {
case 'JSNoSuchMethodError':
// Return null if getting capabilities is currently not supported.
return null;
default:
throw CameraException(
CameraErrorCodes.unknown,
'An unknown error occured when getting the video track capabilities.',
);
}
}
}
return facingMode;
}
/// Maps the given [facingMode] to [CameraLensDirection].
///
/// The following values for the facing mode are supported:
/// https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings/facingMode
CameraLensDirection mapFacingModeToLensDirection(String facingMode) {
switch (facingMode) {
case 'user':
return CameraLensDirection.front;
case 'environment':
return CameraLensDirection.back;
case 'left':
case 'right':
default:
return CameraLensDirection.external;
}
}
/// Maps the given [facingMode] to [CameraType].
///
/// See [CameraMetadata.facingMode] for more details.
CameraType mapFacingModeToCameraType(String facingMode) {
switch (facingMode) {
case 'user':
return CameraType.user;
case 'environment':
return CameraType.environment;
case 'left':
case 'right':
default:
return CameraType.user;
}
}
/// Maps the given [resolutionPreset] to [Size].
Size mapResolutionPresetToSize(ResolutionPreset resolutionPreset) {
switch (resolutionPreset) {
case ResolutionPreset.max:
case ResolutionPreset.ultraHigh:
return Size(3840, 2160);
case ResolutionPreset.veryHigh:
return Size(1920, 1080);
case ResolutionPreset.high:
return Size(1280, 720);
case ResolutionPreset.medium:
return Size(720, 480);
case ResolutionPreset.low:
default:
return Size(320, 240);
}
}
}