[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(