#include "camera.h"
namespace camera_windows {
constexpr char kCameraAccessDenied[] = "CameraAccessDenied";
constexpr char kCameraError[] = "camera_error";
constexpr char kPluginDisposed[] = "plugin_disposed";
std::string GetErrorCode(CameraResult result) {
assert(result != CameraResult::kSuccess);
switch (result) {
case CameraResult::kAccessDenied:
return kCameraAccessDenied;
case CameraResult::kSuccess:
case CameraResult::kError:
default:
return kCameraError;
}
}
CameraImpl::CameraImpl(const std::string& device_id)
: device_id_(device_id), Camera(device_id) {}
CameraImpl::~CameraImpl() {
OnCameraClosing();
capture_controller_ = nullptr;
SendErrorForPendingResults(kPluginDisposed,
"Plugin disposed before request was handled");
}
bool CameraImpl::InitCamera(flutter::TextureRegistrar* texture_registrar,
flutter::BinaryMessenger* messenger,
const PlatformMediaSettings& media_settings) {
auto capture_controller_factory =
std::make_unique<CaptureControllerFactoryImpl>();
return InitCamera(std::move(capture_controller_factory), texture_registrar,
messenger, media_settings);
}
bool CameraImpl::InitCamera(
std::unique_ptr<CaptureControllerFactory> capture_controller_factory,
flutter::TextureRegistrar* texture_registrar,
flutter::BinaryMessenger* messenger,
const PlatformMediaSettings& media_settings) {
assert(!device_id_.empty());
messenger_ = messenger;
capture_controller_ =
capture_controller_factory->CreateCaptureController(this);
return capture_controller_->InitCaptureDevice(texture_registrar, device_id_,
media_settings);
}
bool CameraImpl::AddPendingVoidResult(
PendingResultType type,
std::function<void(std::optional<FlutterError> reply)> result) {
assert(result);
return AddPendingResult(type, result);
}
bool CameraImpl::AddPendingIntResult(
PendingResultType type,
std::function<void(ErrorOr<int64_t> reply)> result) {
assert(result);
return AddPendingResult(type, result);
}
bool CameraImpl::AddPendingStringResult(
PendingResultType type,
std::function<void(ErrorOr<std::string> reply)> result) {
assert(result);
return AddPendingResult(type, result);
}
bool CameraImpl::AddPendingSizeResult(
PendingResultType type,
std::function<void(ErrorOr<PlatformSize> reply)> result) {
assert(result);
return AddPendingResult(type, result);
}
bool CameraImpl::AddPendingResult(PendingResultType type,
CameraImpl::AsyncResult result) {
auto it = pending_results_.find(type);
if (it != pending_results_.end()) {
std::visit(
[](auto&& r) {
r(FlutterError("Duplicate request", "Method handler already called"));
},
result);
return false;
}
pending_results_.insert(std::make_pair(type, std::move(result)));
return true;
}
std::function<void(std::optional<FlutterError> reply)>
CameraImpl::GetPendingVoidResultByType(PendingResultType type) {
std::optional<AsyncResult> result = GetPendingResultByType(type);
if (!result) {
return nullptr;
}
return std::get<std::function<void(std::optional<FlutterError>)>>(
result.value());
}
std::function<void(ErrorOr<int64_t> reply)>
CameraImpl::GetPendingIntResultByType(PendingResultType type) {
std::optional<AsyncResult> result = GetPendingResultByType(type);
if (!result) {
return nullptr;
}
return std::get<std::function<void(ErrorOr<int64_t>)>>(result.value());
}
std::function<void(ErrorOr<std::string> reply)>
CameraImpl::GetPendingStringResultByType(PendingResultType type) {
std::optional<AsyncResult> result = GetPendingResultByType(type);
if (!result) {
return nullptr;
}
return std::get<std::function<void(ErrorOr<std::string>)>>(result.value());
}
std::function<void(ErrorOr<PlatformSize> reply)>
CameraImpl::GetPendingSizeResultByType(PendingResultType type) {
std::optional<AsyncResult> result = GetPendingResultByType(type);
if (!result) {
return nullptr;
}
return std::get<std::function<void(ErrorOr<PlatformSize>)>>(result.value());
}
std::optional<CameraImpl::AsyncResult> CameraImpl::GetPendingResultByType(
PendingResultType type) {
auto it = pending_results_.find(type);
if (it == pending_results_.end()) {
return std::nullopt;
}
CameraImpl::AsyncResult result = std::move(it->second);
pending_results_.erase(it);
return result;
}
bool CameraImpl::HasPendingResultByType(PendingResultType type) const {
auto it = pending_results_.find(type);
return it != pending_results_.end();
}
void CameraImpl::SendErrorForPendingResults(const std::string& error_code,
const std::string& description) {
for (const auto& pending_result : pending_results_) {
std::visit(
[&error_code, &description](auto&& result) {
result(FlutterError(error_code, description));
},
pending_result.second);
}
pending_results_.clear();
}
CameraEventApi* CameraImpl::GetEventApi() {
assert(messenger_);
assert(camera_id_);
if (!event_api_) {
std::string suffix = std::to_string(camera_id_);
event_api_ = std::make_unique<CameraEventApi>(messenger_, suffix);
}
return event_api_.get();
}
void CameraImpl::OnCreateCaptureEngineSucceeded(int64_t texture_id) {
camera_id_ = texture_id;
auto pending_result =
GetPendingIntResultByType(PendingResultType::kCreateCamera);
if (pending_result) {
pending_result(texture_id);
}
}
void CameraImpl::OnCreateCaptureEngineFailed(CameraResult result,
const std::string& error) {
auto pending_result =
GetPendingIntResultByType(PendingResultType::kCreateCamera);
if (pending_result) {
std::string error_code = GetErrorCode(result);
pending_result(FlutterError(error_code, error));
}
}
void CameraImpl::OnStartPreviewSucceeded(int32_t width, int32_t height) {
auto pending_result =
GetPendingSizeResultByType(PendingResultType::kInitialize);
if (pending_result) {
pending_result(
PlatformSize(static_cast<double>(width), static_cast<double>(height)));
}
};
void CameraImpl::OnStartPreviewFailed(CameraResult result,
const std::string& error) {
auto pending_result =
GetPendingSizeResultByType(PendingResultType::kInitialize);
if (pending_result) {
std::string error_code = GetErrorCode(result);
pending_result(FlutterError(error_code, error));
}
};
void CameraImpl::OnResumePreviewSucceeded() {
auto pending_result =
GetPendingVoidResultByType(PendingResultType::kResumePreview);
if (pending_result) {
pending_result(std::nullopt);
}
}
void CameraImpl::OnResumePreviewFailed(CameraResult result,
const std::string& error) {
auto pending_result =
GetPendingVoidResultByType(PendingResultType::kResumePreview);
if (pending_result) {
std::string error_code = GetErrorCode(result);
pending_result(FlutterError(error_code, error));
}
}
void CameraImpl::OnPausePreviewSucceeded() {
auto pending_result =
GetPendingVoidResultByType(PendingResultType::kPausePreview);
if (pending_result) {
pending_result(std::nullopt);
}
}
void CameraImpl::OnPausePreviewFailed(CameraResult result,
const std::string& error) {
auto pending_result =
GetPendingVoidResultByType(PendingResultType::kPausePreview);
if (pending_result) {
std::string error_code = GetErrorCode(result);
pending_result(FlutterError(error_code, error));
}
}
void CameraImpl::OnStartRecordSucceeded() {
auto pending_result =
GetPendingVoidResultByType(PendingResultType::kStartRecord);
if (pending_result) {
pending_result(std::nullopt);
}
};
void CameraImpl::OnStartRecordFailed(CameraResult result,
const std::string& error) {
auto pending_result =
GetPendingVoidResultByType(PendingResultType::kStartRecord);
if (pending_result) {
std::string error_code = GetErrorCode(result);
pending_result(FlutterError(error_code, error));
}
};
void CameraImpl::OnStopRecordSucceeded(const std::string& file_path) {
auto pending_result =
GetPendingStringResultByType(PendingResultType::kStopRecord);
if (pending_result) {
pending_result(file_path);
}
};
void CameraImpl::OnStopRecordFailed(CameraResult result,
const std::string& error) {
auto pending_result =
GetPendingStringResultByType(PendingResultType::kStopRecord);
if (pending_result) {
std::string error_code = GetErrorCode(result);
pending_result(FlutterError(error_code, error));
}
};
void CameraImpl::OnTakePictureSucceeded(const std::string& file_path) {
auto pending_result =
GetPendingStringResultByType(PendingResultType::kTakePicture);
if (pending_result) {
pending_result(file_path);
}
};
void CameraImpl::OnTakePictureFailed(CameraResult result,
const std::string& error) {
auto pending_take_picture_result =
GetPendingStringResultByType(PendingResultType::kTakePicture);
if (pending_take_picture_result) {
std::string error_code = GetErrorCode(result);
pending_take_picture_result(FlutterError(error_code, error));
}
};
void CameraImpl::OnCaptureError(CameraResult result, const std::string& error) {
if (messenger_ && camera_id_ >= 0) {
GetEventApi()->Error(
error,
[]() {}, [](const FlutterError& error) {});
}
std::string error_code = GetErrorCode(result);
SendErrorForPendingResults(error_code, error);
}
void CameraImpl::OnCameraClosing() {
if (messenger_ && camera_id_ >= 0) {
GetEventApi()->CameraClosing([]() {}, [](const FlutterError& error) {});
}
}
}