Add telemetry to measure usage, perf, and errors in Desktop Capturers.

As part of adding the new WgcCapturerWin implementation of the
DesktopCapturer interface, we should ensure that we can measure the
health and success of this new code. In order to quantify that, I've
added telemetry to measure the usage of each capturer implementation,
the time taken to capture a frame, and any errors that are encountered
in the new implementation.

I've also set the capturer id property of frames so that we can measure
error rates and performance of each implementation in Chromium as well.

This CL must be completed after this Chromium CL lands:
2806094: Add histograms to record new WebRTC DesktopCapturer telemetry | https://chromium-review.googlesource.com/c/chromium/src/+/2806094

Bug: webrtc:9273
Change-Id: I33b0a008568a4df4f95e705271badc3313872f17
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/214060
Commit-Queue: Austin Orion <auorion@microsoft.com>
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#33716}
diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn
index 3f170fe..4281bec 100644
--- a/modules/desktop_capture/BUILD.gn
+++ b/modules/desktop_capture/BUILD.gn
@@ -326,6 +326,8 @@
     "cropping_window_capturer.h",
     "desktop_and_cursor_composer.cc",
     "desktop_and_cursor_composer.h",
+    "desktop_capture_metrics_helper.cc",
+    "desktop_capture_metrics_helper.h",
     "desktop_capture_options.cc",
     "desktop_capture_options.h",
     "desktop_capturer.cc",
diff --git a/modules/desktop_capture/desktop_capture_metrics_helper.cc b/modules/desktop_capture/desktop_capture_metrics_helper.cc
new file mode 100644
index 0000000..6b741ef
--- /dev/null
+++ b/modules/desktop_capture/desktop_capture_metrics_helper.cc
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/desktop_capture/desktop_capture_metrics_helper.h"
+
+#include "modules/desktop_capture/desktop_capture_types.h"
+#include "system_wrappers/include/metrics.h"
+
+namespace webrtc {
+namespace {
+// This enum is logged via UMA so entries should not be reordered or have their
+// values changed. This should also be kept in sync with the values in the
+// DesktopCapturerId namespace.
+enum class SequentialDesktopCapturerId {
+  kUnknown = 0,
+  kWgcCapturerWin = 1,
+  kScreenCapturerWinMagnifier = 2,
+  kWindowCapturerWinGdi = 3,
+  kScreenCapturerWinGdi = 4,
+  kScreenCapturerWinDirectx = 5,
+  kMaxValue = kScreenCapturerWinDirectx
+};
+}  // namespace
+
+void RecordCapturerImpl(uint32_t capturer_id) {
+  SequentialDesktopCapturerId sequential_id;
+  switch (capturer_id) {
+    case DesktopCapturerId::kWgcCapturerWin:
+      sequential_id = SequentialDesktopCapturerId::kWgcCapturerWin;
+      break;
+    case DesktopCapturerId::kScreenCapturerWinMagnifier:
+      sequential_id = SequentialDesktopCapturerId::kScreenCapturerWinMagnifier;
+      break;
+    case DesktopCapturerId::kWindowCapturerWinGdi:
+      sequential_id = SequentialDesktopCapturerId::kWindowCapturerWinGdi;
+      break;
+    case DesktopCapturerId::kScreenCapturerWinGdi:
+      sequential_id = SequentialDesktopCapturerId::kScreenCapturerWinGdi;
+      break;
+    case DesktopCapturerId::kScreenCapturerWinDirectx:
+      sequential_id = SequentialDesktopCapturerId::kScreenCapturerWinDirectx;
+      break;
+    case DesktopCapturerId::kUnknown:
+    default:
+      sequential_id = SequentialDesktopCapturerId::kUnknown;
+  }
+  RTC_HISTOGRAM_ENUMERATION(
+      "WebRTC.DesktopCapture.Win.DesktopCapturerImpl",
+      static_cast<int>(sequential_id),
+      static_cast<int>(SequentialDesktopCapturerId::kMaxValue));
+}
+
+}  // namespace webrtc
diff --git a/modules/desktop_capture/desktop_capture_metrics_helper.h b/modules/desktop_capture/desktop_capture_metrics_helper.h
new file mode 100644
index 0000000..37542b8
--- /dev/null
+++ b/modules/desktop_capture/desktop_capture_metrics_helper.h
@@ -0,0 +1,22 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_METRICS_HELPER_H_
+#define MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_METRICS_HELPER_H_
+
+#include <stdint.h>
+
+namespace webrtc {
+
+void RecordCapturerImpl(uint32_t capturer_id);
+
+}  // namespace webrtc
+
+#endif  // MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_METRICS_HELPER_H_
diff --git a/modules/desktop_capture/desktop_capture_types.h b/modules/desktop_capture/desktop_capture_types.h
index 5031cbf..5f9966b 100644
--- a/modules/desktop_capture/desktop_capture_types.h
+++ b/modules/desktop_capture/desktop_capture_types.h
@@ -36,8 +36,11 @@
 
 const ScreenId kInvalidScreenId = -2;
 
-// An integer to attach to each DesktopFrame to differentiate the generator of
-// the frame.
+// Integers to attach to each DesktopFrame to differentiate the generator of
+// the frame. The entries in this namespace should remain in sync with the
+// SequentialDesktopCapturerId enum, which is logged via UMA.
+// |kScreenCapturerWinGdi| and |kScreenCapturerWinDirectx| values are preserved
+// to maintain compatibility
 namespace DesktopCapturerId {
 constexpr uint32_t CreateFourCC(char a, char b, char c, char d) {
   return ((static_cast<uint32_t>(a)) | (static_cast<uint32_t>(b) << 8) |
@@ -45,6 +48,9 @@
 }
 
 constexpr uint32_t kUnknown = 0;
+constexpr uint32_t kWgcCapturerWin = 1;
+constexpr uint32_t kScreenCapturerWinMagnifier = 2;
+constexpr uint32_t kWindowCapturerWinGdi = 3;
 constexpr uint32_t kScreenCapturerWinGdi = CreateFourCC('G', 'D', 'I', ' ');
 constexpr uint32_t kScreenCapturerWinDirectx = CreateFourCC('D', 'X', 'G', 'I');
 }  // namespace DesktopCapturerId
diff --git a/modules/desktop_capture/win/screen_capturer_win_directx.cc b/modules/desktop_capture/win/screen_capturer_win_directx.cc
index df3bee8..1556d7c 100644
--- a/modules/desktop_capture/win/screen_capturer_win_directx.cc
+++ b/modules/desktop_capture/win/screen_capturer_win_directx.cc
@@ -16,12 +16,15 @@
 #include <utility>
 #include <vector>
 
+#include "modules/desktop_capture/desktop_capture_metrics_helper.h"
+#include "modules/desktop_capture/desktop_capture_types.h"
 #include "modules/desktop_capture/desktop_frame.h"
 #include "modules/desktop_capture/win/screen_capture_utils.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/time_utils.h"
 #include "rtc_base/trace_event.h"
+#include "system_wrappers/include/metrics.h"
 
 namespace webrtc {
 
@@ -106,6 +109,7 @@
 void ScreenCapturerWinDirectx::Start(Callback* callback) {
   RTC_DCHECK(!callback_);
   RTC_DCHECK(callback);
+  RecordCapturerImpl(DesktopCapturerId::kScreenCapturerWinDirectx);
 
   callback_ = callback;
 }
@@ -169,8 +173,13 @@
     case DuplicateResult::SUCCEEDED: {
       std::unique_ptr<DesktopFrame> frame =
           frames_.current_frame()->frame()->Share();
-      frame->set_capture_time_ms((rtc::TimeNanos() - capture_start_time_nanos) /
-                                 rtc::kNumNanosecsPerMillisec);
+
+      int capture_time_ms = (rtc::TimeNanos() - capture_start_time_nanos) /
+                            rtc::kNumNanosecsPerMillisec;
+      RTC_HISTOGRAM_COUNTS_1000(
+          "WebRTC.DesktopCapture.Win.DirectXCapturerFrameTime",
+          capture_time_ms);
+      frame->set_capture_time_ms(capture_time_ms);
       frame->set_capturer_id(DesktopCapturerId::kScreenCapturerWinDirectx);
 
       // TODO(julien.isorce): http://crbug.com/945468. Set the icc profile on
diff --git a/modules/desktop_capture/win/screen_capturer_win_gdi.cc b/modules/desktop_capture/win/screen_capturer_win_gdi.cc
index bf6cb16..dc27344 100644
--- a/modules/desktop_capture/win/screen_capturer_win_gdi.cc
+++ b/modules/desktop_capture/win/screen_capturer_win_gdi.cc
@@ -12,7 +12,9 @@
 
 #include <utility>
 
+#include "modules/desktop_capture/desktop_capture_metrics_helper.h"
 #include "modules/desktop_capture/desktop_capture_options.h"
+#include "modules/desktop_capture/desktop_capture_types.h"
 #include "modules/desktop_capture/desktop_frame.h"
 #include "modules/desktop_capture/desktop_frame_win.h"
 #include "modules/desktop_capture/desktop_region.h"
@@ -24,6 +26,7 @@
 #include "rtc_base/logging.h"
 #include "rtc_base/time_utils.h"
 #include "rtc_base/trace_event.h"
+#include "system_wrappers/include/metrics.h"
 
 namespace webrtc {
 
@@ -92,8 +95,12 @@
                                GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
   frame->mutable_updated_region()->SetRect(
       DesktopRect::MakeSize(frame->size()));
-  frame->set_capture_time_ms((rtc::TimeNanos() - capture_start_time_nanos) /
-                             rtc::kNumNanosecsPerMillisec);
+
+  int capture_time_ms = (rtc::TimeNanos() - capture_start_time_nanos) /
+                        rtc::kNumNanosecsPerMillisec;
+  RTC_HISTOGRAM_COUNTS_1000(
+      "WebRTC.DesktopCapture.Win.ScreenGdiCapturerFrameTime", capture_time_ms);
+  frame->set_capture_time_ms(capture_time_ms);
   frame->set_capturer_id(DesktopCapturerId::kScreenCapturerWinGdi);
   callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
 }
@@ -112,6 +119,7 @@
 void ScreenCapturerWinGdi::Start(Callback* callback) {
   RTC_DCHECK(!callback_);
   RTC_DCHECK(callback);
+  RecordCapturerImpl(DesktopCapturerId::kScreenCapturerWinGdi);
 
   callback_ = callback;
 
diff --git a/modules/desktop_capture/win/screen_capturer_win_magnifier.cc b/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
index 1a7bbc1..214eb0e 100644
--- a/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
+++ b/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
@@ -12,7 +12,9 @@
 
 #include <utility>
 
+#include "modules/desktop_capture/desktop_capture_metrics_helper.h"
 #include "modules/desktop_capture/desktop_capture_options.h"
+#include "modules/desktop_capture/desktop_capture_types.h"
 #include "modules/desktop_capture/desktop_frame.h"
 #include "modules/desktop_capture/desktop_frame_win.h"
 #include "modules/desktop_capture/desktop_region.h"
@@ -23,6 +25,7 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/time_utils.h"
+#include "system_wrappers/include/metrics.h"
 
 namespace webrtc {
 
@@ -62,6 +65,8 @@
 void ScreenCapturerWinMagnifier::Start(Callback* callback) {
   RTC_DCHECK(!callback_);
   RTC_DCHECK(callback);
+  RecordCapturerImpl(DesktopCapturerId::kScreenCapturerWinMagnifier);
+
   callback_ = callback;
 
   if (!InitializeMagnifier()) {
@@ -115,8 +120,13 @@
                                GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
   frame->mutable_updated_region()->SetRect(
       DesktopRect::MakeSize(frame->size()));
-  frame->set_capture_time_ms((rtc::TimeNanos() - capture_start_time_nanos) /
-                             rtc::kNumNanosecsPerMillisec);
+
+  int capture_time_ms = (rtc::TimeNanos() - capture_start_time_nanos) /
+                        rtc::kNumNanosecsPerMillisec;
+  RTC_HISTOGRAM_COUNTS_1000(
+      "WebRTC.DesktopCapture.Win.MagnifierCapturerFrameTime", capture_time_ms);
+  frame->set_capture_time_ms(capture_time_ms);
+  frame->set_capturer_id(DesktopCapturerId::kScreenCapturerWinMagnifier);
   callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
 }
 
diff --git a/modules/desktop_capture/win/wgc_capture_session.cc b/modules/desktop_capture/win/wgc_capture_session.cc
index 7ff2f93..48c5686 100644
--- a/modules/desktop_capture/win/wgc_capture_session.cc
+++ b/modules/desktop_capture/win/wgc_capture_session.cc
@@ -13,6 +13,7 @@
 #include <windows.graphics.capture.interop.h>

 #include <windows.graphics.directX.direct3d11.interop.h>

 #include <wrl.h>

+

 #include <memory>

 #include <utility>

 #include <vector>

@@ -20,8 +21,10 @@
 #include "modules/desktop_capture/win/wgc_desktop_frame.h"

 #include "rtc_base/checks.h"

 #include "rtc_base/logging.h"

+#include "rtc_base/time_utils.h"

 #include "rtc_base/win/create_direct3d_device.h"

 #include "rtc_base/win/get_activation_factory.h"

+#include "system_wrappers/include/metrics.h"

 

 using Microsoft::WRL::ComPtr;

 namespace WGC = ABI::Windows::Graphics::Capture;

@@ -39,6 +42,54 @@
 // for a new frame.

 const int kNumBuffers = 1;

 

+// These values are persisted to logs. Entries should not be renumbered and

+// numeric values should never be reused.

+enum class StartCaptureResult {

+  kSuccess = 0,

+  kSourceClosed = 1,

+  kAddClosedFailed = 2,

+  kDxgiDeviceCastFailed = 3,

+  kD3dDelayLoadFailed = 4,

+  kD3dDeviceCreationFailed = 5,

+  kFramePoolActivationFailed = 6,

+  kFramePoolCastFailed = 7,

+  kGetItemSizeFailed = 8,

+  kCreateFreeThreadedFailed = 9,

+  kCreateCaptureSessionFailed = 10,

+  kStartCaptureFailed = 11,

+  kMaxValue = kStartCaptureFailed

+};

+

+// These values are persisted to logs. Entries should not be renumbered and

+// numeric values should never be reused.

+enum class GetFrameResult {

+  kSuccess = 0,

+  kItemClosed = 1,

+  kTryGetNextFrameFailed = 2,

+  kFrameDropped = 3,

+  kGetSurfaceFailed = 4,

+  kDxgiInterfaceAccessFailed = 5,

+  kTexture2dCastFailed = 6,

+  kCreateMappedTextureFailed = 7,

+  kMapFrameFailed = 8,

+  kGetContentSizeFailed = 9,

+  kResizeMappedTextureFailed = 10,

+  kRecreateFramePoolFailed = 11,

+  kMaxValue = kRecreateFramePoolFailed

+};

+

+void RecordStartCaptureResult(StartCaptureResult error) {

+  RTC_HISTOGRAM_ENUMERATION(

+      "WebRTC.DesktopCapture.Win.WgcCaptureSessionStartResult",

+      static_cast<int>(error), static_cast<int>(StartCaptureResult::kMaxValue));

+}

+

+void RecordGetFrameResult(GetFrameResult error) {

+  RTC_HISTOGRAM_ENUMERATION(

+      "WebRTC.DesktopCapture.Win.WgcCaptureSessionGetFrameResult",

+      static_cast<int>(error), static_cast<int>(GetFrameResult::kMaxValue));

+}

+

 }  // namespace

 

 WgcCaptureSession::WgcCaptureSession(ComPtr<ID3D11Device> d3d11_device,

@@ -52,6 +103,7 @@
 

   if (item_closed_) {

     RTC_LOG(LS_ERROR) << "The target source has been closed.";

+    RecordStartCaptureResult(StartCaptureResult::kSourceClosed);

     return E_ABORT;

   }

 

@@ -67,57 +119,80 @@
           this, &WgcCaptureSession::OnItemClosed);

   EventRegistrationToken item_closed_token;

   HRESULT hr = item_->add_Closed(closed_handler.Get(), &item_closed_token);

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordStartCaptureResult(StartCaptureResult::kAddClosedFailed);

     return hr;

+  }

 

   ComPtr<IDXGIDevice> dxgi_device;

   hr = d3d11_device_->QueryInterface(IID_PPV_ARGS(&dxgi_device));

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordStartCaptureResult(StartCaptureResult::kDxgiDeviceCastFailed);

     return hr;

+  }

 

-  if (!ResolveCoreWinRTDirect3DDelayload())

+  if (!ResolveCoreWinRTDirect3DDelayload()) {

+    RecordStartCaptureResult(StartCaptureResult::kD3dDelayLoadFailed);

     return E_FAIL;

+  }

 

   hr = CreateDirect3DDeviceFromDXGIDevice(dxgi_device.Get(), &direct3d_device_);

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordStartCaptureResult(StartCaptureResult::kD3dDeviceCreationFailed);

     return hr;

+  }

 

   ComPtr<WGC::IDirect3D11CaptureFramePoolStatics> frame_pool_statics;

   hr = GetActivationFactory<

       ABI::Windows::Graphics::Capture::IDirect3D11CaptureFramePoolStatics,

       RuntimeClass_Windows_Graphics_Capture_Direct3D11CaptureFramePool>(

       &frame_pool_statics);

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordStartCaptureResult(StartCaptureResult::kFramePoolActivationFailed);

     return hr;

+  }

 

   // Cast to FramePoolStatics2 so we can use CreateFreeThreaded and avoid the

   // need to have a DispatcherQueue. We don't listen for the FrameArrived event,

   // so there's no difference.

   ComPtr<WGC::IDirect3D11CaptureFramePoolStatics2> frame_pool_statics2;

   hr = frame_pool_statics->QueryInterface(IID_PPV_ARGS(&frame_pool_statics2));

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordStartCaptureResult(StartCaptureResult::kFramePoolCastFailed);

     return hr;

+  }

 

   ABI::Windows::Graphics::SizeInt32 item_size;

   hr = item_.Get()->get_Size(&item_size);

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordStartCaptureResult(StartCaptureResult::kGetItemSizeFailed);

     return hr;

+  }

 

   previous_size_ = item_size;

 

   hr = frame_pool_statics2->CreateFreeThreaded(direct3d_device_.Get(),

                                                kPixelFormat, kNumBuffers,

                                                item_size, &frame_pool_);

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordStartCaptureResult(StartCaptureResult::kCreateFreeThreadedFailed);

     return hr;

+  }

 

   hr = frame_pool_->CreateCaptureSession(item_.Get(), &session_);

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordStartCaptureResult(StartCaptureResult::kCreateCaptureSessionFailed);

     return hr;

+  }

 

   hr = session_->StartCapture();

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RTC_LOG(LS_ERROR) << "Failed to start CaptureSession: " << hr;

+    RecordStartCaptureResult(StartCaptureResult::kStartCaptureFailed);

     return hr;

+  }

+

+  RecordStartCaptureResult(StartCaptureResult::kSuccess);

 

   is_capture_started_ = true;

   return hr;

@@ -129,6 +204,7 @@
 

   if (item_closed_) {

     RTC_LOG(LS_ERROR) << "The target source has been closed.";

+    RecordGetFrameResult(GetFrameResult::kItemClosed);

     return E_ABORT;

   }

 

@@ -136,35 +212,48 @@
 

   ComPtr<WGC::IDirect3D11CaptureFrame> capture_frame;

   HRESULT hr = frame_pool_->TryGetNextFrame(&capture_frame);

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RTC_LOG(LS_ERROR) << "TryGetNextFrame failed: " << hr;

+    RecordGetFrameResult(GetFrameResult::kTryGetNextFrameFailed);

     return hr;

+  }

 

-  if (!capture_frame)

+  if (!capture_frame) {

+    RecordGetFrameResult(GetFrameResult::kFrameDropped);

     return hr;

+  }

 

   // We need to get this CaptureFrame as an ID3D11Texture2D so that we can get

   // the raw image data in the format required by the DesktopFrame interface.

   ComPtr<ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface>

       d3d_surface;

   hr = capture_frame->get_Surface(&d3d_surface);

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordGetFrameResult(GetFrameResult::kGetSurfaceFailed);

     return hr;

+  }

 

   ComPtr<Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess>

       direct3DDxgiInterfaceAccess;

   hr = d3d_surface->QueryInterface(IID_PPV_ARGS(&direct3DDxgiInterfaceAccess));

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordGetFrameResult(GetFrameResult::kDxgiInterfaceAccessFailed);

     return hr;

+  }

 

   ComPtr<ID3D11Texture2D> texture_2D;

   hr = direct3DDxgiInterfaceAccess->GetInterface(IID_PPV_ARGS(&texture_2D));

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordGetFrameResult(GetFrameResult::kTexture2dCastFailed);

     return hr;

+  }

 

   if (!mapped_texture_) {

     hr = CreateMappedTexture(texture_2D);

-    if (FAILED(hr))

+    if (FAILED(hr)) {

+      RecordGetFrameResult(GetFrameResult::kCreateMappedTextureFailed);

       return hr;

+    }

   }

 

   // We need to copy |texture_2D| into |mapped_texture_| as the latter has the

@@ -178,13 +267,17 @@
   hr = d3d_context->Map(mapped_texture_.Get(), /*subresource_index=*/0,

                         D3D11_MAP_READ, /*D3D11_MAP_FLAG_DO_NOT_WAIT=*/0,

                         &map_info);

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordGetFrameResult(GetFrameResult::kMapFrameFailed);

     return hr;

+  }

 

   ABI::Windows::Graphics::SizeInt32 new_size;

   hr = capture_frame->get_ContentSize(&new_size);

-  if (FAILED(hr))

+  if (FAILED(hr)) {

+    RecordGetFrameResult(GetFrameResult::kGetContentSizeFailed);

     return hr;

+  }

 

   // If the size has changed since the last capture, we must be sure to use

   // the smaller dimensions. Otherwise we might overrun our buffer, or

@@ -217,15 +310,21 @@
   if (previous_size_.Height != new_size.Height ||

       previous_size_.Width != new_size.Width) {

     hr = CreateMappedTexture(texture_2D, new_size.Width, new_size.Height);

-    if (FAILED(hr))

+    if (FAILED(hr)) {

+      RecordGetFrameResult(GetFrameResult::kResizeMappedTextureFailed);

       return hr;

+    }

 

     hr = frame_pool_->Recreate(direct3d_device_.Get(), kPixelFormat,

                                kNumBuffers, new_size);

-    if (FAILED(hr))

+    if (FAILED(hr)) {

+      RecordGetFrameResult(GetFrameResult::kRecreateFramePoolFailed);

       return hr;

+    }

   }

 

+  RecordGetFrameResult(GetFrameResult::kSuccess);

+

   previous_size_ = new_size;

   return hr;

 }

diff --git a/modules/desktop_capture/win/wgc_capturer_win.cc b/modules/desktop_capture/win/wgc_capturer_win.cc
index 4c5ca29..0b4d974 100644
--- a/modules/desktop_capture/win/wgc_capturer_win.cc
+++ b/modules/desktop_capture/win/wgc_capturer_win.cc
@@ -12,14 +12,39 @@
 

 #include <utility>

 

+#include "modules/desktop_capture/desktop_capture_metrics_helper.h"

+#include "modules/desktop_capture/desktop_capture_types.h"

 #include "modules/desktop_capture/win/wgc_desktop_frame.h"

 #include "rtc_base/logging.h"

+#include "rtc_base/time_utils.h"

+#include "system_wrappers/include/metrics.h"

 

 namespace WGC = ABI::Windows::Graphics::Capture;

 using Microsoft::WRL::ComPtr;

 

 namespace webrtc {

 

+namespace {

+

+enum class WgcCapturerResult {

+  kSuccess = 0,

+  kNoDirect3dDevice = 1,

+  kNoSourceSelected = 2,

+  kItemCreationFailure = 3,

+  kSessionStartFailure = 4,

+  kGetFrameFailure = 5,

+  kFrameDropped = 6,

+  kMaxValue = kFrameDropped

+};

+

+void RecordWgcCapturerResult(WgcCapturerResult error) {

+  RTC_HISTOGRAM_ENUMERATION("WebRTC.DesktopCapture.Win.WgcCapturerResult",

+                            static_cast<int>(error),

+                            static_cast<int>(WgcCapturerResult::kMaxValue));

+}

+

+}  // namespace

+

 WgcCapturerWin::WgcCapturerWin(

     std::unique_ptr<WgcCaptureSourceFactory> source_factory,

     std::unique_ptr<SourceEnumerator> source_enumerator)

@@ -55,6 +80,7 @@
 void WgcCapturerWin::Start(Callback* callback) {

   RTC_DCHECK(!callback_);

   RTC_DCHECK(callback);

+  RecordCapturerImpl(DesktopCapturerId::kWgcCapturerWin);

 

   callback_ = callback;

 

@@ -89,6 +115,7 @@
     RTC_LOG(LS_ERROR) << "Source hasn't been selected";

     callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT,

                                /*frame=*/nullptr);

+    RecordWgcCapturerResult(WgcCapturerResult::kNoSourceSelected);

     return;

   }

 

@@ -96,9 +123,12 @@
     RTC_LOG(LS_ERROR) << "No D3D11D3evice, cannot capture.";

     callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT,

                                /*frame=*/nullptr);

+    RecordWgcCapturerResult(WgcCapturerResult::kNoDirect3dDevice);

     return;

   }

 

+  int64_t capture_start_time_nanos = rtc::TimeNanos();

+

   HRESULT hr;

   WgcCaptureSession* capture_session = nullptr;

   std::map<SourceId, WgcCaptureSession>::iterator session_iter =

@@ -110,6 +140,7 @@
       RTC_LOG(LS_ERROR) << "Failed to create a GraphicsCaptureItem: " << hr;

       callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT,

                                  /*frame=*/nullptr);

+      RecordWgcCapturerResult(WgcCapturerResult::kItemCreationFailure);

       return;

     }

 

@@ -131,6 +162,7 @@
       ongoing_captures_.erase(capture_source_->GetSourceId());

       callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT,

                                  /*frame=*/nullptr);

+      RecordWgcCapturerResult(WgcCapturerResult::kSessionStartFailure);

       return;

     }

   }

@@ -142,15 +174,24 @@
     ongoing_captures_.erase(capture_source_->GetSourceId());

     callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT,

                                /*frame=*/nullptr);

+    RecordWgcCapturerResult(WgcCapturerResult::kGetFrameFailure);

     return;

   }

 

   if (!frame) {

     callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_TEMPORARY,

                                /*frame=*/nullptr);

+    RecordWgcCapturerResult(WgcCapturerResult::kFrameDropped);

     return;

   }

 

+  int capture_time_ms = (rtc::TimeNanos() - capture_start_time_nanos) /

+                        rtc::kNumNanosecsPerMillisec;

+  RTC_HISTOGRAM_COUNTS_1000("WebRTC.DesktopCapture.Win.WgcCapturerFrameTime",

+                            capture_time_ms);

+  frame->set_capture_time_ms(capture_time_ms);

+  frame->set_capturer_id(DesktopCapturerId::kWgcCapturerWin);

+  RecordWgcCapturerResult(WgcCapturerResult::kSuccess);

   callback_->OnCaptureResult(DesktopCapturer::Result::SUCCESS,

                              std::move(frame));

 }

diff --git a/modules/desktop_capture/win/wgc_capturer_win_unittest.cc b/modules/desktop_capture/win/wgc_capturer_win_unittest.cc
index 25866c2..732de7d 100644
--- a/modules/desktop_capture/win/wgc_capturer_win_unittest.cc
+++ b/modules/desktop_capture/win/wgc_capturer_win_unittest.cc
@@ -22,8 +22,10 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/thread.h"
+#include "rtc_base/time_utils.h"
 #include "rtc_base/win/scoped_com_initializer.h"
 #include "rtc_base/win/windows_version.h"
+#include "system_wrappers/include/metrics.h"
 #include "test/gtest.h"
 
 namespace webrtc {
@@ -32,6 +34,21 @@
 const char kWindowThreadName[] = "wgc_capturer_test_window_thread";
 const WCHAR kWindowTitle[] = L"WGC Capturer Test Window";
 
+const char kCapturerImplHistogram[] =
+    "WebRTC.DesktopCapture.Win.DesktopCapturerImpl";
+
+const char kCapturerResultHistogram[] =
+    "WebRTC.DesktopCapture.Win.WgcCapturerResult";
+const int kSuccess = 0;
+const int kSessionStartFailure = 4;
+
+const char kCaptureSessionResultHistogram[] =
+    "WebRTC.DesktopCapture.Win.WgcCaptureSessionStartResult";
+const int kSourceClosed = 1;
+
+const char kCaptureTimeHistogram[] =
+    "WebRTC.DesktopCapture.Win.WgcCapturerFrameTime";
+
 const int kSmallWindowWidth = 200;
 const int kSmallWindowHeight = 100;
 const int kMediumWindowWidth = 300;
@@ -181,6 +198,10 @@
 
     EXPECT_EQ(result_, DesktopCapturer::Result::SUCCESS);
     EXPECT_TRUE(frame_);
+
+    EXPECT_GT(metrics::NumEvents(kCapturerResultHistogram, kSuccess),
+              successful_captures_);
+    ++successful_captures_;
   }
 
   void ValidateFrame(int expected_width, int expected_height) {
@@ -233,6 +254,7 @@
   intptr_t source_id_;
   bool window_open_ = false;
   DesktopCapturer::Result result_;
+  int successful_captures_ = 0;
   std::unique_ptr<DesktopFrame> frame_;
   std::unique_ptr<DesktopCapturer> capturer_;
 };
@@ -271,11 +293,42 @@
   EXPECT_TRUE(capturer_->SelectSource(source_id_));
 
   capturer_->Start(this);
+  EXPECT_GE(metrics::NumEvents(kCapturerImplHistogram,
+                               DesktopCapturerId::kWgcCapturerWin),
+            1);
+
   DoCapture();
   EXPECT_GT(frame_->size().width(), 0);
   EXPECT_GT(frame_->size().height(), 0);
 }
 
+TEST_P(WgcCapturerWinTest, CaptureTime) {
+  if (GetParam() == CaptureType::kWindowCapture) {
+    SetUpForWindowCapture();
+  } else {
+    SetUpForScreenCapture();
+  }
+
+  EXPECT_TRUE(capturer_->SelectSource(source_id_));
+  capturer_->Start(this);
+
+  int64_t start_time;
+  do {
+    start_time = rtc::TimeNanos();
+    capturer_->CaptureFrame();
+  } while (result_ == DesktopCapturer::Result::ERROR_TEMPORARY);
+
+  int capture_time_ms =
+      (rtc::TimeNanos() - start_time) / rtc::kNumNanosecsPerMillisec;
+  EXPECT_TRUE(frame_);
+
+  // The test may measure the time slightly differently than the capturer. So we
+  // just check if it's within 5 ms.
+  EXPECT_NEAR(frame_->capture_time_ms(), capture_time_ms, 5);
+  EXPECT_GE(
+      metrics::NumEvents(kCaptureTimeHistogram, frame_->capture_time_ms()), 1);
+}
+
 INSTANTIATE_TEST_SUITE_P(SourceAgnostic,
                          WgcCapturerWinTest,
                          ::testing::Values(CaptureType::kWindowCapture,
@@ -403,6 +456,10 @@
   if (result_ == DesktopCapturer::Result::SUCCESS)
     capturer_->CaptureFrame();
 
+  EXPECT_GE(metrics::NumEvents(kCapturerResultHistogram, kSessionStartFailure),
+            1);
+  EXPECT_GE(metrics::NumEvents(kCaptureSessionResultHistogram, kSourceClosed),
+            1);
   EXPECT_EQ(result_, DesktopCapturer::Result::ERROR_PERMANENT);
 }
 
diff --git a/modules/desktop_capture/win/window_capturer_win_gdi.cc b/modules/desktop_capture/win/window_capturer_win_gdi.cc
index 04cd7f6..5f7c788 100644
--- a/modules/desktop_capture/win/window_capturer_win_gdi.cc
+++ b/modules/desktop_capture/win/window_capturer_win_gdi.cc
@@ -17,6 +17,8 @@
 #include <vector>
 
 #include "modules/desktop_capture/cropped_desktop_frame.h"
+#include "modules/desktop_capture/desktop_capture_metrics_helper.h"
+#include "modules/desktop_capture/desktop_capture_types.h"
 #include "modules/desktop_capture/desktop_capturer.h"
 #include "modules/desktop_capture/desktop_frame_win.h"
 #include "modules/desktop_capture/win/screen_capture_utils.h"
@@ -25,8 +27,10 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/string_utils.h"
+#include "rtc_base/time_utils.h"
 #include "rtc_base/trace_event.h"
 #include "rtc_base/win32.h"
+#include "system_wrappers/include/metrics.h"
 
 namespace webrtc {
 
@@ -143,14 +147,23 @@
 void WindowCapturerWinGdi::Start(Callback* callback) {
   RTC_DCHECK(!callback_);
   RTC_DCHECK(callback);
+  RecordCapturerImpl(DesktopCapturerId::kWindowCapturerWinGdi);
 
   callback_ = callback;
 }
 
 void WindowCapturerWinGdi::CaptureFrame() {
   RTC_DCHECK(callback_);
+  int64_t capture_start_time_nanos = rtc::TimeNanos();
 
   CaptureResults results = CaptureFrame(/*capture_owned_windows*/ true);
+
+  int capture_time_ms = (rtc::TimeNanos() - capture_start_time_nanos) /
+                        rtc::kNumNanosecsPerMillisec;
+  RTC_HISTOGRAM_COUNTS_1000(
+      "WebRTC.DesktopCapture.Win.WindowGdiCapturerFrameTime", capture_time_ms);
+  results.frame->set_capture_time_ms(capture_time_ms);
+  results.frame->set_capturer_id(DesktopCapturerId::kWindowCapturerWinGdi);
   callback_->OnCaptureResult(results.result, std::move(results.frame));
 }