blob: 88c1ae317fb42664389d81f39a71b4c064c3b60d [file] [log] [blame]
// 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