| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/views/media_preview/media_preview_metrics.h" |
| |
| #include <string> |
| |
| #include "base/check_op.h" |
| #include "base/metrics/histogram.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/strings/strcat.h" |
| |
| using base::StrCat; |
| |
| namespace media_preview_metrics { |
| |
| namespace { |
| |
| constexpr char kUiPrefix[] = "MediaPreviews.UI."; |
| constexpr char kDeviceSelection[] = "DeviceSelection."; |
| constexpr char kPreview[] = "Preview."; |
| |
| base::HistogramBase* GetMediaPreviewDurationHistogram(const std::string& name) { |
| // Duration buckets as powers of 2 |
| const std::vector<int> custom_ranges{1, 2, 4, 8, 16, 32, 64, 128, 256, 512}; |
| return base::CustomHistogram::FactoryGet( |
| name, custom_ranges, base::HistogramBase::kUmaTargetedHistogramFlag); |
| } |
| |
| base::HistogramBase* GetTotalVisiblePreviewDurationHistogram( |
| const std::string& name) { |
| // Duration buckets in milliseconds. |
| const std::vector<int> custom_ranges{50, 125, 250, 500, 750, 1000, |
| 1333, 1666, 2000, 2500, 3000, 4000}; |
| return base::CustomHistogram::FactoryGet( |
| name, custom_ranges, base::HistogramBase::kUmaTargetedHistogramFlag); |
| } |
| |
| base::HistogramBase* GetPreviewDelayTimeHistogram(const std::string& name) { |
| return GetTotalVisiblePreviewDurationHistogram(name); |
| } |
| |
| const char* GetUiLocationString(UiLocation location) { |
| switch (location) { |
| case UiLocation::kPermissionPrompt: |
| return "Permissions"; |
| case UiLocation::kPageInfo: |
| return "PageInfo"; |
| } |
| } |
| |
| const char* GetPreviewTypeString(const Context& context) { |
| switch (context.preview_type) { |
| case PreviewType::kCamera: |
| return "Camera"; |
| case PreviewType::kMic: |
| return "Mic"; |
| case PreviewType::kCameraAndMic: |
| return "CameraAndMic"; |
| } |
| } |
| |
| // Doesn't accept a Context with PreviewType::kCameraAndMic. |
| std::string GetUiLocationAndPreviewTypeString(const Context& context) { |
| CHECK_NE(context.preview_type, PreviewType::kCameraAndMic); |
| return StrCat({GetUiLocationString(context.ui_location), ".", |
| GetPreviewTypeString(context)}); |
| } |
| |
| std::string GetUiLocationAndPreviewTypeStringAllowingBoth( |
| const Context& context) { |
| if (context.preview_type == PreviewType::kCameraAndMic) { |
| CHECK_EQ(context.ui_location, UiLocation::kPermissionPrompt); |
| } |
| return StrCat({GetUiLocationString(context.ui_location), ".", |
| GetPreviewTypeString(context)}); |
| } |
| |
| void UmaHistogramLinearCounts(const std::string& name, |
| int sample, |
| int minimum, |
| int maximum, |
| size_t bucket_count) { |
| base::HistogramBase* histogram = base::LinearHistogram::FactoryGet( |
| name, minimum, maximum, bucket_count, |
| base::HistogramBase::kUmaTargetedHistogramFlag); |
| histogram->Add(sample); |
| } |
| |
| } // anonymous namespace |
| |
| Context::Context(UiLocation ui_location, PreviewType preview_type) |
| : ui_location(ui_location), preview_type(preview_type) {} |
| |
| Context::~Context() = default; |
| |
| Context::Context(const Context& other) = default; |
| Context::Context(Context&& other) = default; |
| |
| void RecordPageInfoNumInUseDevices(const Context& context, int devices) { |
| CHECK_EQ(context.ui_location, UiLocation::kPageInfo); |
| std::string metric_name = |
| StrCat({kUiPrefix, GetUiLocationAndPreviewTypeString(context), |
| ".NumInUseDevices"}); |
| base::UmaHistogramExactLinear(metric_name, devices, /*exclusive_max=*/5); |
| } |
| |
| void RecordMediaPreviewDuration(const Context& context, |
| const base::TimeDelta& delta) { |
| std::string location_plus_type = |
| GetUiLocationAndPreviewTypeStringAllowingBoth(context); |
| std::string metric_name = |
| StrCat({kUiPrefix, location_plus_type, ".Duration"}); |
| GetMediaPreviewDurationHistogram(metric_name)->Add(delta.InSeconds()); |
| } |
| |
| void RecordDeviceSelectionTotalDevices(const Context& context, int devices) { |
| std::string metric_name = |
| StrCat({kUiPrefix, kDeviceSelection, |
| GetUiLocationAndPreviewTypeString(context), ".NumDevices"}); |
| base::UmaHistogramExactLinear(metric_name, devices, /*exclusive_max=*/5); |
| } |
| |
| void RecordDeviceSelectionAction( |
| const Context& context, |
| MediaPreviewDeviceSelectionUserAction user_action) { |
| std::string metric_name = |
| StrCat({kUiPrefix, kDeviceSelection, |
| GetUiLocationAndPreviewTypeString(context), ".Action"}); |
| base::UmaHistogramEnumeration(metric_name, user_action); |
| } |
| |
| void RecordPreviewCameraPixelHeight(const Context& context, int pixel_height) { |
| CHECK_EQ(context.preview_type, PreviewType::kCamera); |
| std::string metric_name = |
| StrCat({kUiPrefix, GetUiLocationString(context.ui_location), |
| ".Camera.PixelHeight"}); |
| // This really has 8 buckets for 1-1080, but we have to add 2 for underflow |
| // and overflow. |
| UmaHistogramLinearCounts(metric_name, pixel_height, /*minimum=*/1, |
| /*maximum=*/1080, /*bucket_count=*/10); |
| } |
| |
| void RecordPreviewVideoExpectedFPS(const Context& context, int expected_fps) { |
| CHECK_EQ(context.preview_type, PreviewType::kCamera); |
| std::string metric_name = |
| StrCat({kUiPrefix, kPreview, GetUiLocationString(context.ui_location), |
| ".Video.ExpectedFPS"}); |
| base::UmaHistogramExactLinear(metric_name, expected_fps, |
| /*exclusive_max=*/61); |
| } |
| |
| void RecordPreviewVideoActualFPS(const Context& context, int actual_fps) { |
| CHECK_EQ(context.preview_type, PreviewType::kCamera); |
| std::string metric_name = |
| StrCat({kUiPrefix, kPreview, GetUiLocationString(context.ui_location), |
| ".Video.ActualFPS"}); |
| base::UmaHistogramExactLinear(metric_name, actual_fps, |
| /*exclusive_max=*/61); |
| } |
| |
| void RecordPreviewVideoFramesRenderedPercent(const Context& context, |
| float percent) { |
| CHECK_EQ(context.preview_type, PreviewType::kCamera); |
| std::string metric_name = |
| StrCat({kUiPrefix, kPreview, GetUiLocationString(context.ui_location), |
| ".Video.RenderedPercent"}); |
| // Convert percentage to 0-100 integer. |
| int integer_percent = std::clamp(percent, /*lo=*/0.0f, /*hi=*/1.0f) * 100; |
| base::UmaHistogramPercentage(metric_name, integer_percent); |
| } |
| |
| void RecordTotalVisiblePreviewDuration(const Context& context, |
| const base::TimeDelta& delta) { |
| CHECK_EQ(context.preview_type, PreviewType::kCamera); |
| std::string metric_name = |
| StrCat({kUiPrefix, kPreview, GetUiLocationString(context.ui_location), |
| ".Video.TotalVisibleDuration"}); |
| GetTotalVisiblePreviewDurationHistogram(metric_name) |
| ->Add(delta.InMilliseconds()); |
| } |
| |
| void RecordTimeToActionWithoutPreview(const Context& context, |
| const base::TimeDelta& delta) { |
| CHECK_EQ(context.preview_type, PreviewType::kCamera); |
| std::string metric_name = |
| StrCat({kUiPrefix, kPreview, GetUiLocationString(context.ui_location), |
| ".Video.TimeToActionWithoutPreview"}); |
| GetPreviewDelayTimeHistogram(metric_name)->Add(delta.InMilliseconds()); |
| } |
| |
| void RecordPreviewDelayTime(const Context& context, |
| const base::TimeDelta& delta) { |
| CHECK_EQ(context.preview_type, PreviewType::kCamera); |
| std::string metric_name = |
| StrCat({kUiPrefix, kPreview, GetUiLocationString(context.ui_location), |
| ".Video.Delay"}); |
| GetPreviewDelayTimeHistogram(metric_name)->Add(delta.InMilliseconds()); |
| } |
| |
| void RecordVideoCaptureError(const Context& context, |
| media::VideoCaptureError received_error) { |
| CHECK_EQ(context.preview_type, PreviewType::kCamera); |
| std::string metric_name = |
| StrCat({kUiPrefix, kPreview, GetUiLocationString(context.ui_location), |
| ".VideoCaptureError"}); |
| base::UmaHistogramEnumeration(metric_name, received_error); |
| } |
| |
| } // namespace media_preview_metrics |