[camera_windows] Improve several error handling scenarios (#6149)
diff --git a/packages/camera/camera_windows/CHANGELOG.md b/packages/camera/camera_windows/CHANGELOG.md
index a1e2a07..a7b8023 100644
--- a/packages/camera/camera_windows/CHANGELOG.md
+++ b/packages/camera/camera_windows/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.0+5
+
+* Fixes bugs in in error handling.
+
## 0.1.0+4
* Allows retrying camera initialization after error.
diff --git a/packages/camera/camera_windows/lib/camera_windows.dart b/packages/camera/camera_windows/lib/camera_windows.dart
index d998863..1413447 100644
--- a/packages/camera/camera_windows/lib/camera_windows.dart
+++ b/packages/camera/camera_windows/lib/camera_windows.dart
@@ -22,7 +22,7 @@
final MethodChannel pluginChannel =
const MethodChannel('plugins.flutter.io/camera_windows');
- /// Camera specific method channels to allow comminicating with specific cameras.
+ /// Camera specific method channels to allow communicating with specific cameras.
final Map<int, MethodChannel> _cameraChannels = <int, MethodChannel>{};
/// The controller that broadcasts events coming from handleCameraMethodCall
diff --git a/packages/camera/camera_windows/pubspec.yaml b/packages/camera/camera_windows/pubspec.yaml
index e9fe021..690ac9f 100644
--- a/packages/camera/camera_windows/pubspec.yaml
+++ b/packages/camera/camera_windows/pubspec.yaml
@@ -2,7 +2,7 @@
description: A Flutter plugin for getting information about and controlling the camera on Windows.
repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_windows
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
-version: 0.1.0+4
+version: 0.1.0+5
environment:
sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/camera/camera_windows/windows/camera.cpp b/packages/camera/camera_windows/windows/camera.cpp
index 617f98f..794b20d 100644
--- a/packages/camera/camera_windows/windows/camera.cpp
+++ b/packages/camera/camera_windows/windows/camera.cpp
@@ -85,9 +85,9 @@
}
void CameraImpl::SendErrorForPendingResults(const std::string& error_code,
- const std::string& descripion) {
+ const std::string& description) {
for (const auto& pending_result : pending_results_) {
- pending_result.second->Error(error_code, descripion);
+ pending_result.second->Error(error_code, description);
}
pending_results_.clear();
}
diff --git a/packages/camera/camera_windows/windows/camera.h b/packages/camera/camera_windows/windows/camera.h
index 429f41a..7374228 100644
--- a/packages/camera/camera_windows/windows/camera.h
+++ b/packages/camera/camera_windows/windows/camera.h
@@ -139,9 +139,9 @@
// error ID and description. Pending results are cleared in the process.
//
// error_code: A string error code describing the error.
- // error_message: A user-readable error message (optional).
+ // description: A user-readable error message (optional).
void SendErrorForPendingResults(const std::string& error_code,
- const std::string& descripion);
+ const std::string& description);
// Called when camera is disposed.
// Sends camera closing message to the cameras method channel.
diff --git a/packages/camera/camera_windows/windows/capture_controller.cpp b/packages/camera/camera_windows/windows/capture_controller.cpp
index 6c89060..0294ce8 100644
--- a/packages/camera/camera_windows/windows/capture_controller.cpp
+++ b/packages/camera/camera_windows/windows/capture_controller.cpp
@@ -237,6 +237,8 @@
return hr;
}
+ // Check MF_CAPTURE_ENGINE_INITIALIZED event handling
+ // for response process.
hr = capture_engine_->Initialize(capture_engine_callback_handler_.Get(),
attributes.Get(), audio_source_.Get(),
video_source_.Get());
@@ -244,7 +246,7 @@
}
void CaptureControllerImpl::ResetCaptureController() {
- if (record_handler_) {
+ if (record_handler_ && record_handler_->CanStop()) {
if (record_handler_->IsContinuousRecording()) {
StopRecord();
} else if (record_handler_->IsTimedRecording()) {
@@ -391,7 +393,7 @@
}
}
-// Finds best mediat type for given source stream index and max height;
+// Finds best media type for given source stream index and max height;
bool FindBestMediaType(DWORD source_stream_index, IMFCaptureSource* source,
IMFMediaType** target_media_type, uint32_t max_height,
uint32_t* target_frame_width,
@@ -533,8 +535,6 @@
// Check MF_CAPTURE_ENGINE_RECORD_STOPPED event handling for response
// process.
if (!record_handler_->StopRecord(capture_engine_.Get())) {
- // Destroy record handler on error cases to make sure state is resetted.
- record_handler_ = nullptr;
return OnRecordStopped(false, "Failed to stop video recording");
}
}
@@ -578,6 +578,8 @@
texture_handler_->UpdateTextureSize(preview_frame_width_,
preview_frame_height_);
+ // TODO(loic-sharma): This does not handle duplicate calls properly.
+ // See: https://github.com/flutter/flutter/issues/108404
if (!preview_handler_) {
preview_handler_ = std::make_unique<PreviewHandler>();
} else if (preview_handler_->IsInitialized()) {
@@ -605,7 +607,7 @@
void CaptureControllerImpl::StopPreview() {
assert(capture_engine_);
- if (!IsInitialized() && !preview_handler_) {
+ if (!IsInitialized() || !preview_handler_) {
return;
}
@@ -619,7 +621,7 @@
void CaptureControllerImpl::PausePreview() {
assert(capture_controller_listener_);
- if (!preview_handler_ && !preview_handler_->IsInitialized()) {
+ if (!preview_handler_ || !preview_handler_->IsInitialized()) {
return capture_controller_listener_->OnPausePreviewFailed(
"Preview not started");
}
@@ -638,7 +640,7 @@
void CaptureControllerImpl::ResumePreview() {
assert(capture_controller_listener_);
- if (!preview_handler_ && !preview_handler_->IsInitialized()) {
+ if (!preview_handler_ || !preview_handler_->IsInitialized()) {
return capture_controller_listener_->OnResumePreviewFailed(
"Preview not started");
}
@@ -722,6 +724,13 @@
void CaptureControllerImpl::OnCaptureEngineInitialized(
bool success, const std::string& error) {
if (capture_controller_listener_) {
+ if (!success) {
+ capture_controller_listener_->OnCreateCaptureEngineFailed(
+ "Failed to initialize capture engine");
+ ResetCaptureController();
+ return;
+ }
+
// Create texture handler and register new texture.
texture_handler_ = std::make_unique<TextureHandler>(texture_registrar_);
@@ -848,7 +857,7 @@
}
if (preview_handler_ && preview_handler_->IsStarting()) {
- // Informs that first frame is captured succeffully and preview has
+ // Informs that first frame is captured successfully and preview has
// started.
OnPreviewStarted(true, "");
}
diff --git a/packages/camera/camera_windows/windows/photo_handler.h b/packages/camera/camera_windows/windows/photo_handler.h
index ef0d98b..c12643b 100644
--- a/packages/camera/camera_windows/windows/photo_handler.h
+++ b/packages/camera/camera_windows/windows/photo_handler.h
@@ -51,7 +51,7 @@
bool TakePhoto(const std::string& file_path, IMFCaptureEngine* capture_engine,
IMFMediaType* base_media_type);
- // Set the photo handler recording state to: kIdel.
+ // Set the photo handler recording state to: kIdle.
void OnPhotoTaken();
// Returns true if photo state is kIdle.
diff --git a/packages/camera/camera_windows/windows/preview_handler.h b/packages/camera/camera_windows/windows/preview_handler.h
index 97b85fc..a10ba63 100644
--- a/packages/camera/camera_windows/windows/preview_handler.h
+++ b/packages/camera/camera_windows/windows/preview_handler.h
@@ -75,7 +75,7 @@
// Returns true if preview state is running or paused.
bool IsInitialized() const {
- return preview_state_ == PreviewState::kRunning &&
+ return preview_state_ == PreviewState::kRunning ||
preview_state_ == PreviewState::kPaused;
}
diff --git a/packages/camera/camera_windows/windows/record_handler.cpp b/packages/camera/camera_windows/windows/record_handler.cpp
index 1cb258e..2e16527 100644
--- a/packages/camera/camera_windows/windows/record_handler.cpp
+++ b/packages/camera/camera_windows/windows/record_handler.cpp
@@ -238,6 +238,7 @@
recording_duration_us_ = 0;
max_video_duration_ms_ = -1;
recording_state_ = RecordState::kNotStarted;
+ type_ = RecordingType::kNone;
}
}
diff --git a/packages/camera/camera_windows/windows/record_handler.h b/packages/camera/camera_windows/windows/record_handler.h
index 0daa7f6..4cbe499 100644
--- a/packages/camera/camera_windows/windows/record_handler.h
+++ b/packages/camera/camera_windows/windows/record_handler.h
@@ -16,6 +16,8 @@
using Microsoft::WRL::ComPtr;
enum class RecordingType {
+ // Camera is not recording.
+ kNone,
// Recording continues until it is stopped with a separate stop command.
kContinuous,
// Recording stops automatically after requested record time is passed.
@@ -109,7 +111,7 @@
uint64_t recording_duration_us_ = 0;
std::string file_path_;
RecordState recording_state_ = RecordState::kNotStarted;
- RecordingType type_;
+ RecordingType type_ = RecordingType::kNone;
ComPtr<IMFCaptureRecordSink> record_sink_;
};
diff --git a/packages/camera/camera_windows/windows/test/camera_test.cpp b/packages/camera/camera_windows/windows/test/camera_test.cpp
index 97e3ce1..50f4953 100644
--- a/packages/camera/camera_windows/windows/test/camera_test.cpp
+++ b/packages/camera/camera_windows/windows/test/camera_test.cpp
@@ -131,7 +131,7 @@
camera->OnCreateCaptureEngineSucceeded(texture_id);
}
-TEST(Camera, OnCreateCaptureEngineFailedReturnsError) {
+TEST(Camera, CreateCaptureEngineReportsError) {
std::unique_ptr<CameraImpl> camera =
std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
std::unique_ptr<MockMethodResult> result =
@@ -140,7 +140,7 @@
std::string error_text = "error_text";
EXPECT_CALL(*result, SuccessInternal).Times(0);
- EXPECT_CALL(*result, ErrorInternal(_, Eq(error_text), _));
+ EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
camera->AddPendingResult(PendingResultType::kCreateCamera, std::move(result));
@@ -169,7 +169,7 @@
camera->OnStartPreviewSucceeded(width, height);
}
-TEST(Camera, OnStartPreviewFailedReturnsError) {
+TEST(Camera, StartPreviewReportsError) {
std::unique_ptr<CameraImpl> camera =
std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
std::unique_ptr<MockMethodResult> result =
@@ -178,7 +178,7 @@
std::string error_text = "error_text";
EXPECT_CALL(*result, SuccessInternal).Times(0);
- EXPECT_CALL(*result, ErrorInternal(_, Eq(error_text), _));
+ EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
camera->AddPendingResult(PendingResultType::kInitialize, std::move(result));
@@ -199,7 +199,7 @@
camera->OnPausePreviewSucceeded();
}
-TEST(Camera, OnPausePreviewFailedReturnsError) {
+TEST(Camera, PausePreviewReportsError) {
std::unique_ptr<CameraImpl> camera =
std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
std::unique_ptr<MockMethodResult> result =
@@ -208,7 +208,7 @@
std::string error_text = "error_text";
EXPECT_CALL(*result, SuccessInternal).Times(0);
- EXPECT_CALL(*result, ErrorInternal(_, Eq(error_text), _));
+ EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
camera->AddPendingResult(PendingResultType::kPausePreview, std::move(result));
@@ -230,7 +230,7 @@
camera->OnResumePreviewSucceeded();
}
-TEST(Camera, OnResumePreviewFailedReturnsError) {
+TEST(Camera, ResumePreviewReportsError) {
std::unique_ptr<CameraImpl> camera =
std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
std::unique_ptr<MockMethodResult> result =
@@ -239,7 +239,7 @@
std::string error_text = "error_text";
EXPECT_CALL(*result, SuccessInternal).Times(0);
- EXPECT_CALL(*result, ErrorInternal(_, Eq(error_text), _));
+ EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
camera->AddPendingResult(PendingResultType::kResumePreview,
std::move(result));
@@ -261,7 +261,7 @@
camera->OnStartRecordSucceeded();
}
-TEST(Camera, OnStartRecordFailedReturnsError) {
+TEST(Camera, StartRecordReportsError) {
std::unique_ptr<CameraImpl> camera =
std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
std::unique_ptr<MockMethodResult> result =
@@ -270,7 +270,7 @@
std::string error_text = "error_text";
EXPECT_CALL(*result, SuccessInternal).Times(0);
- EXPECT_CALL(*result, ErrorInternal(_, Eq(error_text), _));
+ EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
camera->AddPendingResult(PendingResultType::kStartRecord, std::move(result));
@@ -293,7 +293,7 @@
camera->OnStopRecordSucceeded(file_path);
}
-TEST(Camera, OnStopRecordFailedReturnsError) {
+TEST(Camera, StopRecordReportsError) {
std::unique_ptr<CameraImpl> camera =
std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
std::unique_ptr<MockMethodResult> result =
@@ -302,7 +302,7 @@
std::string error_text = "error_text";
EXPECT_CALL(*result, SuccessInternal).Times(0);
- EXPECT_CALL(*result, ErrorInternal(_, Eq(error_text), _));
+ EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
camera->AddPendingResult(PendingResultType::kStopRecord, std::move(result));
@@ -315,7 +315,7 @@
std::unique_ptr<MockMethodResult> result =
std::make_unique<MockMethodResult>();
- std::string file_path = "C:\temp\filename.jpeg";
+ std::string file_path = "C:\\temp\\filename.jpeg";
EXPECT_CALL(*result, ErrorInternal).Times(0);
EXPECT_CALL(*result, SuccessInternal(Pointee(EncodableValue(file_path))));
@@ -325,7 +325,7 @@
camera->OnTakePictureSucceeded(file_path);
}
-TEST(Camera, OnTakePictureFailedReturnsError) {
+TEST(Camera, TakePictureReportsError) {
std::unique_ptr<CameraImpl> camera =
std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
std::unique_ptr<MockMethodResult> result =
@@ -334,7 +334,7 @@
std::string error_text = "error_text";
EXPECT_CALL(*result, SuccessInternal).Times(0);
- EXPECT_CALL(*result, ErrorInternal(_, Eq(error_text), _));
+ EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
camera->AddPendingResult(PendingResultType::kTakePicture, std::move(result));
@@ -350,7 +350,7 @@
std::unique_ptr<MockBinaryMessenger> binary_messenger =
std::make_unique<MockBinaryMessenger>();
- std::string file_path = "C:\temp\filename.mp4";
+ std::string file_path = "C:\\temp\\filename.mp4";
int64_t camera_id = 12345;
std::string camera_channel =
std::string("plugins.flutter.io/camera_windows/camera") +
diff --git a/packages/camera/camera_windows/windows/test/capture_controller_test.cpp b/packages/camera/camera_windows/windows/test/capture_controller_test.cpp
index 083f823..776c150 100644
--- a/packages/camera/camera_windows/windows/test/capture_controller_test.cpp
+++ b/packages/camera/camera_windows/windows/test/capture_controller_test.cpp
@@ -70,35 +70,10 @@
engine->CreateFakeEvent(S_OK, MF_CAPTURE_ENGINE_INITIALIZED);
}
-void MockStartPreview(CaptureControllerImpl* capture_controller,
- MockCaptureSource* capture_source,
- MockCapturePreviewSink* preview_sink,
- MockTextureRegistrar* texture_registrar,
- MockCaptureEngine* engine, MockCamera* camera,
- std::unique_ptr<uint8_t[]> mock_source_buffer,
- uint32_t mock_source_buffer_size,
- uint32_t mock_preview_width, uint32_t mock_preview_height,
- int64_t mock_texture_id) {
- EXPECT_CALL(*engine, GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_PREVIEW, _))
- .Times(1)
- .WillOnce([src_sink = preview_sink](MF_CAPTURE_ENGINE_SINK_TYPE sink_type,
- IMFCaptureSink** target_sink) {
- *target_sink = src_sink;
- src_sink->AddRef();
- return S_OK;
- });
-
- EXPECT_CALL(*preview_sink, RemoveAllStreams).Times(1).WillOnce(Return(S_OK));
- EXPECT_CALL(*preview_sink, AddStream).Times(1).WillOnce(Return(S_OK));
- EXPECT_CALL(*preview_sink, SetSampleCallback)
- .Times(1)
- .WillOnce([sink = preview_sink](
- DWORD dwStreamSinkIndex,
- IMFCaptureEngineOnSampleCallback* pCallback) -> HRESULT {
- sink->sample_callback_ = pCallback;
- return S_OK;
- });
-
+void MockAvailableMediaTypes(MockCaptureEngine* engine,
+ MockCaptureSource* capture_source,
+ uint32_t mock_preview_width,
+ uint32_t mock_preview_height) {
EXPECT_CALL(*engine, GetSource)
.Times(1)
.WillOnce(
@@ -142,6 +117,39 @@
(*media_type)->AddRef();
return S_OK;
});
+}
+
+void MockStartPreview(CaptureControllerImpl* capture_controller,
+ MockCapturePreviewSink* preview_sink,
+ MockTextureRegistrar* texture_registrar,
+ MockCaptureEngine* engine, MockCamera* camera,
+ std::unique_ptr<uint8_t[]> mock_source_buffer,
+ uint32_t mock_source_buffer_size,
+ uint32_t mock_preview_width, uint32_t mock_preview_height,
+ int64_t mock_texture_id) {
+ EXPECT_CALL(*engine, GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_PREVIEW, _))
+ .Times(1)
+ .WillOnce([src_sink = preview_sink](MF_CAPTURE_ENGINE_SINK_TYPE sink_type,
+ IMFCaptureSink** target_sink) {
+ *target_sink = src_sink;
+ src_sink->AddRef();
+ return S_OK;
+ });
+
+ EXPECT_CALL(*preview_sink, RemoveAllStreams).Times(1).WillOnce(Return(S_OK));
+ EXPECT_CALL(*preview_sink, AddStream).Times(1).WillOnce(Return(S_OK));
+ EXPECT_CALL(*preview_sink, SetSampleCallback)
+ .Times(1)
+ .WillOnce([sink = preview_sink](
+ DWORD dwStreamSinkIndex,
+ IMFCaptureEngineOnSampleCallback* pCallback) -> HRESULT {
+ sink->sample_callback_ = pCallback;
+ return S_OK;
+ });
+
+ ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+ MockAvailableMediaTypes(engine, capture_source.Get(), mock_preview_width,
+ mock_preview_height);
EXPECT_CALL(*engine, StartPreview()).Times(1).WillOnce(Return(S_OK));
@@ -169,6 +177,21 @@
mock_source_buffer_size);
}
+void MockPhotoSink(MockCaptureEngine* engine,
+ MockCapturePhotoSink* photo_sink) {
+ EXPECT_CALL(*engine, GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_PHOTO, _))
+ .Times(1)
+ .WillOnce([src_sink = photo_sink](MF_CAPTURE_ENGINE_SINK_TYPE sink_type,
+ IMFCaptureSink** target_sink) {
+ *target_sink = src_sink;
+ src_sink->AddRef();
+ return S_OK;
+ });
+ EXPECT_CALL(*photo_sink, RemoveAllStreams).Times(1).WillOnce(Return(S_OK));
+ EXPECT_CALL(*photo_sink, AddStream).Times(1).WillOnce(Return(S_OK));
+ EXPECT_CALL(*photo_sink, SetOutputFileName).Times(1).WillOnce(Return(S_OK));
+}
+
void MockRecordStart(CaptureControllerImpl* capture_controller,
MockCaptureEngine* engine,
MockCaptureRecordSink* record_sink, MockCamera* camera,
@@ -204,7 +227,7 @@
std::unique_ptr<MockTextureRegistrar> texture_registrar =
std::make_unique<MockTextureRegistrar>();
- uint64_t mock_texture_id = 1234;
+ int64_t mock_texture_id = 1234;
// Init capture controller with mocks and tests
MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
@@ -225,7 +248,7 @@
std::unique_ptr<MockTextureRegistrar> texture_registrar =
std::make_unique<MockTextureRegistrar>();
- uint64_t mock_texture_id = 1234;
+ int64_t mock_texture_id = 1234;
// Init capture controller once with mocks and tests
MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
@@ -264,14 +287,12 @@
capture_controller->SetAudioSource(
reinterpret_cast<IMFMediaSource*>(audio_source.Get()));
+ // Cause initialization to fail
+ EXPECT_CALL(*engine.Get(), Initialize).Times(1).WillOnce(Return(E_FAIL));
+
EXPECT_CALL(*texture_registrar, RegisterTexture).Times(0);
EXPECT_CALL(*texture_registrar, UnregisterTexture).Times(0);
EXPECT_CALL(*camera, OnCreateCaptureEngineSucceeded).Times(0);
-
- EXPECT_CALL(*engine.Get(), Initialize)
- .Times(1)
- .WillOnce(Return(E_ACCESSDENIED));
-
EXPECT_CALL(*camera,
OnCreateCaptureEngineFailed(Eq("Failed to create camera")))
.Times(1);
@@ -288,6 +309,60 @@
engine = nullptr;
}
+TEST(CaptureController, ReportsInitializedErrorEvent) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+
+ int64_t mock_texture_id = 1234;
+
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ EXPECT_CALL(*camera, OnCreateCaptureEngineFailed(
+ Eq("Failed to initialize capture engine")))
+ .Times(1);
+ EXPECT_CALL(*camera, OnCreateCaptureEngineSucceeded).Times(0);
+
+ // Send initialization failed event
+ engine->CreateFakeEvent(E_FAIL, MF_CAPTURE_ENGINE_INITIALIZED);
+
+ capture_controller = nullptr;
+ camera = nullptr;
+ texture_registrar = nullptr;
+ engine = nullptr;
+}
+
+TEST(CaptureController, ReportsCaptureEngineErrorEvent) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+
+ int64_t mock_texture_id = 1234;
+
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ EXPECT_CALL(*(camera.get()), OnCaptureError(Eq("Unspecified error")))
+ .Times(1);
+
+ // Send error event.
+ engine->CreateFakeEvent(E_FAIL, MF_CAPTURE_ENGINE_ERROR);
+
+ capture_controller = nullptr;
+ camera = nullptr;
+ texture_registrar = nullptr;
+ engine = nullptr;
+}
+
TEST(CaptureController, StartPreviewStartsProcessingSamples) {
ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
std::unique_ptr<MockCamera> camera =
@@ -297,14 +372,13 @@
std::unique_ptr<MockTextureRegistrar> texture_registrar =
std::make_unique<MockTextureRegistrar>();
- uint64_t mock_texture_id = 1234;
+ int64_t mock_texture_id = 1234;
// Initialize capture controller to be able to start preview
MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
engine.Get(), camera.get(), mock_texture_id);
ComPtr<MockCapturePreviewSink> preview_sink = new MockCapturePreviewSink();
- ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
// Let's keep these small for mock texture data. Two pixels should be
// enough.
@@ -332,11 +406,10 @@
}
// Start preview and run preview tests
- MockStartPreview(capture_controller.get(), capture_source.Get(),
- preview_sink.Get(), texture_registrar.get(), engine.Get(),
- camera.get(), std::move(mock_source_buffer),
- mock_texture_data_size, mock_preview_width,
- mock_preview_height, mock_texture_id);
+ MockStartPreview(capture_controller.get(), preview_sink.Get(),
+ texture_registrar.get(), engine.Get(), camera.get(),
+ std::move(mock_source_buffer), mock_texture_data_size,
+ mock_preview_width, mock_preview_height, mock_texture_id);
// Test texture processing
EXPECT_TRUE(texture_registrar->texture_);
@@ -377,6 +450,73 @@
texture_registrar = nullptr;
}
+TEST(CaptureController, ReportsStartPreviewError) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+
+ int64_t mock_texture_id = 1234;
+
+ // Initialize capture controller to be able to start preview
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+ MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+ // Cause start preview to fail
+ EXPECT_CALL(*engine.Get(), GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_PREVIEW, _))
+ .Times(1)
+ .WillOnce(Return(E_FAIL));
+
+ EXPECT_CALL(*engine.Get(), StartPreview).Times(0);
+ EXPECT_CALL(*engine.Get(), StopPreview).Times(0);
+ EXPECT_CALL(*camera, OnStartPreviewSucceeded).Times(0);
+ EXPECT_CALL(*camera,
+ OnStartPreviewFailed(Eq("Failed to start video preview")))
+ .Times(1);
+
+ capture_controller->StartPreview();
+
+ capture_controller = nullptr;
+ engine = nullptr;
+ camera = nullptr;
+ texture_registrar = nullptr;
+}
+
+// TODO(loic-sharma): Test duplicate calls to start preview.
+
+TEST(CaptureController, IgnoresStartPreviewErrorEvent) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+
+ int64_t mock_texture_id = 1234;
+
+ // Initialize capture controller to be able to start preview
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ EXPECT_CALL(*camera, OnStartPreviewFailed).Times(0);
+ EXPECT_CALL(*camera, OnCreateCaptureEngineSucceeded).Times(0);
+
+ // Send a start preview error event
+ engine->CreateFakeEvent(E_FAIL, MF_CAPTURE_ENGINE_PREVIEW_STARTED);
+
+ capture_controller = nullptr;
+ camera = nullptr;
+ texture_registrar = nullptr;
+ engine = nullptr;
+}
+
TEST(CaptureController, StartRecordSuccess) {
ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
std::unique_ptr<MockCamera> camera =
@@ -386,23 +526,16 @@
std::unique_ptr<MockTextureRegistrar> texture_registrar =
std::make_unique<MockTextureRegistrar>();
- uint64_t mock_texture_id = 1234;
+ int64_t mock_texture_id = 1234;
// Initialize capture controller to be able to start preview
MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
engine.Get(), camera.get(), mock_texture_id);
- ComPtr<MockCapturePreviewSink> preview_sink = new MockCapturePreviewSink();
ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
- std::unique_ptr<uint8_t[]> mock_source_buffer =
- std::make_unique<uint8_t[]>(0);
-
- // Start preview to be able to start record
- MockStartPreview(capture_controller.get(), capture_source.Get(),
- preview_sink.Get(), texture_registrar.get(), engine.Get(),
- camera.get(), std::move(mock_source_buffer), 0, 1, 1,
- mock_texture_id);
+ // Prepare fake media types
+ MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
// Start record
ComPtr<MockCaptureRecordSink> record_sink = new MockCaptureRecordSink();
@@ -422,6 +555,109 @@
record_sink = nullptr;
}
+TEST(CaptureController, ReportsStartRecordError) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+
+ int64_t mock_texture_id = 1234;
+
+ // Initialize capture controller to be able to start preview
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+ // Prepare fake media types
+ MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+ // Cause start record to fail
+ EXPECT_CALL(*engine.Get(), GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_RECORD, _))
+ .Times(1)
+ .WillOnce(Return(E_FAIL));
+
+ EXPECT_CALL(*engine.Get(), StartRecord).Times(0);
+ EXPECT_CALL(*engine.Get(), StopRecord).Times(0);
+ EXPECT_CALL(*camera, OnStartRecordSucceeded).Times(0);
+ EXPECT_CALL(*camera,
+ OnStartRecordFailed(Eq("Failed to start video recording")))
+ .Times(1);
+
+ capture_controller->StartRecord("mock_path", -1);
+
+ capture_controller = nullptr;
+ texture_registrar = nullptr;
+ engine = nullptr;
+ camera = nullptr;
+}
+
+TEST(CaptureController, ReportsStartRecordErrorEvent) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+
+ int64_t mock_texture_id = 1234;
+
+ // Initialize capture controller to be able to start preview
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+ // Prepare fake media types
+ MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+ // Start record
+ ComPtr<MockCaptureRecordSink> record_sink = new MockCaptureRecordSink();
+ std::string mock_path_to_video = "mock_path_to_video";
+
+ EXPECT_CALL(*engine.Get(), StartRecord()).Times(1).WillOnce(Return(S_OK));
+
+ EXPECT_CALL(*engine.Get(), GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_RECORD, _))
+ .Times(1)
+ .WillOnce([src_sink = record_sink](MF_CAPTURE_ENGINE_SINK_TYPE sink_type,
+ IMFCaptureSink** target_sink) {
+ *target_sink = src_sink.Get();
+ src_sink->AddRef();
+ return S_OK;
+ });
+
+ EXPECT_CALL(*record_sink.Get(), RemoveAllStreams)
+ .Times(1)
+ .WillOnce(Return(S_OK));
+ EXPECT_CALL(*record_sink.Get(), AddStream)
+ .Times(2)
+ .WillRepeatedly(Return(S_OK));
+ EXPECT_CALL(*record_sink.Get(), SetOutputFileName)
+ .Times(1)
+ .WillOnce(Return(S_OK));
+
+ capture_controller->StartRecord(mock_path_to_video, -1);
+
+ // Send a start record failed event
+ EXPECT_CALL(*camera, OnStartRecordSucceeded).Times(0);
+ EXPECT_CALL(*camera, OnStartRecordFailed(Eq("Unspecified error"))).Times(1);
+
+ engine->CreateFakeEvent(E_FAIL, MF_CAPTURE_ENGINE_RECORD_STARTED);
+
+ // Destructor shouldn't attempt to stop the recording that failed to start.
+ EXPECT_CALL(*engine.Get(), StopRecord).Times(0);
+
+ capture_controller = nullptr;
+ texture_registrar = nullptr;
+ engine = nullptr;
+ camera = nullptr;
+ record_sink = nullptr;
+}
+
TEST(CaptureController, StopRecordSuccess) {
ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
std::unique_ptr<MockCamera> camera =
@@ -431,23 +667,16 @@
std::unique_ptr<MockTextureRegistrar> texture_registrar =
std::make_unique<MockTextureRegistrar>();
- uint64_t mock_texture_id = 1234;
+ int64_t mock_texture_id = 1234;
// Initialize capture controller to be able to start preview
MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
engine.Get(), camera.get(), mock_texture_id);
- ComPtr<MockCapturePreviewSink> preview_sink = new MockCapturePreviewSink();
ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
- std::unique_ptr<uint8_t[]> mock_source_buffer =
- std::make_unique<uint8_t[]>(0);
-
- // Start preview to be able to start record
- MockStartPreview(capture_controller.get(), capture_source.Get(),
- preview_sink.Get(), texture_registrar.get(), engine.Get(),
- camera.get(), std::move(mock_source_buffer), 0, 1, 1,
- mock_texture_id);
+ // Prepare fake media types
+ MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
// Start record
ComPtr<MockCaptureRecordSink> record_sink = new MockCaptureRecordSink();
@@ -463,6 +692,8 @@
// OnStopRecordSucceeded should be called with mocked file path
EXPECT_CALL(*camera, OnStopRecordSucceeded(Eq(mock_path_to_video))).Times(1);
+ EXPECT_CALL(*camera, OnStopRecordFailed).Times(0);
+
engine->CreateFakeEvent(S_OK, MF_CAPTURE_ENGINE_RECORD_STOPPED);
capture_controller = nullptr;
@@ -472,6 +703,88 @@
record_sink = nullptr;
}
+TEST(CaptureController, ReportsStopRecordError) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+
+ int64_t mock_texture_id = 1234;
+
+ // Initialize capture controller to be able to start preview
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+ // Prepare fake media types
+ MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+ // Start record
+ ComPtr<MockCaptureRecordSink> record_sink = new MockCaptureRecordSink();
+ MockRecordStart(capture_controller.get(), engine.Get(), record_sink.Get(),
+ camera.get(), "mock_path_to_video");
+
+ // Cause stop record to fail
+ EXPECT_CALL(*(engine.Get()), StopRecord(true, false))
+ .Times(1)
+ .WillOnce(Return(E_FAIL));
+
+ EXPECT_CALL(*camera, OnStopRecordSucceeded).Times(0);
+ EXPECT_CALL(*camera, OnStopRecordFailed(Eq("Failed to stop video recording")))
+ .Times(1);
+
+ capture_controller->StopRecord();
+
+ capture_controller = nullptr;
+ texture_registrar = nullptr;
+ engine = nullptr;
+ camera = nullptr;
+ record_sink = nullptr;
+}
+
+TEST(CaptureController, ReportsStopRecordErrorEvent) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+
+ int64_t mock_texture_id = 1234;
+
+ // Initialize capture controller to be able to start preview
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+ // Prepare fake media types
+ MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+ // Start record
+ ComPtr<MockCaptureRecordSink> record_sink = new MockCaptureRecordSink();
+ std::string mock_path_to_video = "mock_path_to_video";
+ MockRecordStart(capture_controller.get(), engine.Get(), record_sink.Get(),
+ camera.get(), mock_path_to_video);
+
+ // Send a stop record failure event
+ EXPECT_CALL(*camera, OnStopRecordSucceeded).Times(0);
+ EXPECT_CALL(*camera, OnStopRecordFailed(Eq("Unspecified error"))).Times(1);
+
+ engine->CreateFakeEvent(E_FAIL, MF_CAPTURE_ENGINE_RECORD_STOPPED);
+
+ capture_controller = nullptr;
+ texture_registrar = nullptr;
+ engine = nullptr;
+ camera = nullptr;
+ record_sink = nullptr;
+}
+
TEST(CaptureController, TakePictureSuccess) {
ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
std::unique_ptr<MockCamera> camera =
@@ -481,42 +794,21 @@
std::unique_ptr<MockTextureRegistrar> texture_registrar =
std::make_unique<MockTextureRegistrar>();
- uint64_t mock_texture_id = 1234;
+ int64_t mock_texture_id = 1234;
- // Initialize capture controller to be able to start preview
+ // Initialize capture controller to be able to take picture
MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
engine.Get(), camera.get(), mock_texture_id);
- ComPtr<MockCapturePreviewSink> preview_sink = new MockCapturePreviewSink();
ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
- std::unique_ptr<uint8_t[]> mock_source_buffer =
- std::make_unique<uint8_t[]>(0);
+ // Prepare fake media types
+ MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
- // Start preview to be able to start record
- MockStartPreview(capture_controller.get(), capture_source.Get(),
- preview_sink.Get(), texture_registrar.get(), engine.Get(),
- camera.get(), std::move(mock_source_buffer), 0, 1, 1,
- mock_texture_id);
-
- // Init photo sink tests
ComPtr<MockCapturePhotoSink> photo_sink = new MockCapturePhotoSink();
- EXPECT_CALL(*(engine.Get()), GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_PHOTO, _))
- .Times(1)
- .WillOnce(
- [src_sink = photo_sink.Get()](MF_CAPTURE_ENGINE_SINK_TYPE sink_type,
- IMFCaptureSink** target_sink) {
- *target_sink = src_sink;
- src_sink->AddRef();
- return S_OK;
- });
- EXPECT_CALL(*(photo_sink.Get()), RemoveAllStreams)
- .Times(1)
- .WillOnce(Return(S_OK));
- EXPECT_CALL(*(photo_sink.Get()), AddStream).Times(1).WillOnce(Return(S_OK));
- EXPECT_CALL(*(photo_sink.Get()), SetOutputFileName)
- .Times(1)
- .WillOnce(Return(S_OK));
+
+ // Initialize photo sink
+ MockPhotoSink(engine.Get(), photo_sink.Get());
// Request photo
std::string mock_path_to_photo = "mock_path_to_photo";
@@ -525,6 +817,7 @@
// OnTakePictureSucceeded should be called with mocked file path
EXPECT_CALL(*camera, OnTakePictureSucceeded(Eq(mock_path_to_photo))).Times(1);
+ EXPECT_CALL(*camera, OnTakePictureFailed).Times(0);
engine->CreateFakeEvent(S_OK, MF_CAPTURE_ENGINE_PHOTO_TAKEN);
capture_controller = nullptr;
@@ -534,6 +827,90 @@
photo_sink = nullptr;
}
+TEST(CaptureController, ReportsTakePictureError) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+
+ int64_t mock_texture_id = 1234;
+
+ // Initialize capture controller to be able to take picture
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+ // Prepare fake media types
+ MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+ ComPtr<MockCapturePhotoSink> photo_sink = new MockCapturePhotoSink();
+
+ // Initialize photo sink
+ MockPhotoSink(engine.Get(), photo_sink.Get());
+
+ // Cause take picture to fail
+ EXPECT_CALL(*(engine.Get()), TakePhoto).Times(1).WillOnce(Return(E_FAIL));
+
+ EXPECT_CALL(*camera, OnTakePictureSucceeded).Times(0);
+ EXPECT_CALL(*camera, OnTakePictureFailed(Eq("Failed to take photo")))
+ .Times(1);
+
+ capture_controller->TakePicture("mock_path_to_photo");
+
+ capture_controller = nullptr;
+ texture_registrar = nullptr;
+ engine = nullptr;
+ camera = nullptr;
+ photo_sink = nullptr;
+}
+
+TEST(CaptureController, ReportsPhotoTakenErrorEvent) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+
+ int64_t mock_texture_id = 1234;
+
+ // Initialize capture controller to be able to take picture
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+ // Prepare fake media types
+ MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+ ComPtr<MockCapturePhotoSink> photo_sink = new MockCapturePhotoSink();
+
+ // Initialize photo sink
+ MockPhotoSink(engine.Get(), photo_sink.Get());
+
+ // Request photo
+ std::string mock_path_to_photo = "mock_path_to_photo";
+ EXPECT_CALL(*(engine.Get()), TakePhoto()).Times(1).WillOnce(Return(S_OK));
+ capture_controller->TakePicture(mock_path_to_photo);
+
+ // Send take picture failed event
+ EXPECT_CALL(*camera, OnTakePictureSucceeded).Times(0);
+ EXPECT_CALL(*camera, OnTakePictureFailed(Eq("Unspecified error"))).Times(1);
+
+ engine->CreateFakeEvent(E_FAIL, MF_CAPTURE_ENGINE_PHOTO_TAKEN);
+
+ capture_controller = nullptr;
+ texture_registrar = nullptr;
+ engine = nullptr;
+ camera = nullptr;
+ photo_sink = nullptr;
+}
+
TEST(CaptureController, PauseResumePreviewSuccess) {
ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
std::unique_ptr<MockCamera> camera =
@@ -543,23 +920,21 @@
std::unique_ptr<MockTextureRegistrar> texture_registrar =
std::make_unique<MockTextureRegistrar>();
- uint64_t mock_texture_id = 1234;
+ int64_t mock_texture_id = 1234;
// Initialize capture controller to be able to start preview
MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
engine.Get(), camera.get(), mock_texture_id);
ComPtr<MockCapturePreviewSink> preview_sink = new MockCapturePreviewSink();
- ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
std::unique_ptr<uint8_t[]> mock_source_buffer =
std::make_unique<uint8_t[]>(0);
// Start preview to be able to start record
- MockStartPreview(capture_controller.get(), capture_source.Get(),
- preview_sink.Get(), texture_registrar.get(), engine.Get(),
- camera.get(), std::move(mock_source_buffer), 0, 1, 1,
- mock_texture_id);
+ MockStartPreview(capture_controller.get(), preview_sink.Get(),
+ texture_registrar.get(), engine.Get(), camera.get(),
+ std::move(mock_source_buffer), 0, 1, 1, mock_texture_id);
EXPECT_CALL(*camera, OnPausePreviewSucceeded()).Times(1);
capture_controller->PausePreview();
@@ -573,5 +948,57 @@
camera = nullptr;
}
+TEST(CaptureController, PausePreviewFailsIfPreviewNotStarted) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+ int64_t mock_texture_id = 1234;
+
+ // Initialize capture controller to be able to start preview
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ // Pause preview fails if not started
+ EXPECT_CALL(*camera, OnPausePreviewFailed(Eq("Preview not started")))
+ .Times(1);
+
+ capture_controller->PausePreview();
+
+ capture_controller = nullptr;
+ texture_registrar = nullptr;
+ engine = nullptr;
+ camera = nullptr;
+}
+
+TEST(CaptureController, ResumePreviewFailsIfPreviewNotStarted) {
+ ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+ std::unique_ptr<MockCamera> camera =
+ std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+ std::unique_ptr<CaptureControllerImpl> capture_controller =
+ std::make_unique<CaptureControllerImpl>(camera.get());
+ std::unique_ptr<MockTextureRegistrar> texture_registrar =
+ std::make_unique<MockTextureRegistrar>();
+ int64_t mock_texture_id = 1234;
+
+ // Initialize capture controller to be able to start preview
+ MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+ engine.Get(), camera.get(), mock_texture_id);
+
+ // Resume preview fails if not started.
+ EXPECT_CALL(*camera, OnResumePreviewFailed(Eq("Preview not started")))
+ .Times(1);
+
+ capture_controller->ResumePreview();
+
+ capture_controller = nullptr;
+ texture_registrar = nullptr;
+ engine = nullptr;
+ camera = nullptr;
+}
+
} // namespace test
} // namespace camera_windows
diff --git a/script/tool/README.md b/script/tool/README.md
index d3beb53..225cda2 100644
--- a/script/tool/README.md
+++ b/script/tool/README.md
@@ -105,6 +105,8 @@
dart run ./script/tool/bin/flutter_plugin_tools.dart native-test --ios --android --no-integration --packages plugin_name
# Run all tests for macOS:
dart run ./script/tool/bin/flutter_plugin_tools.dart native-test --macos --packages plugin_name
+# Run all tests for Windows:
+dart run ./script/tool/bin/flutter_plugin_tools.dart native-test --windows --packages plugin_name
```
### Update README.md from Example Sources
diff --git a/script/tool/lib/src/common/package_state_utils.dart b/script/tool/lib/src/common/package_state_utils.dart
index 437bbf6..a03d643 100644
--- a/script/tool/lib/src/common/package_state_utils.dart
+++ b/script/tool/lib/src/common/package_state_utils.dart
@@ -35,7 +35,7 @@
/// [changedPaths] should be a list of POSIX-style paths from a common root,
/// and [relativePackagePath] should be the path to [package] from that same
/// root. Commonly these will come from `gitVersionFinder.getChangedFiles()`
-/// and `getRelativePoixPath(package.directory, gitDir.path)` respectively;
+/// and `getRelativePosixPath(package.directory, gitDir.path)` respectively;
/// they are arguments mainly to allow for caching the changed paths for an
/// entire command run.
PackageChangeState checkPackageChangeState(