blob: 061a96cf75e733ae5360c73e88531ec27c3da5b0 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/mojo/services/playback_events_recorder.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace media {
namespace {
void RecordEventWithValueAt(const char* name,
int64_t value,
base::TimeTicks time) {
base::RecordComputedActionAt(base::StrCat({"WebEngine.Media.", name, ":",
base::NumberToString(value)}),
time);
}
void RecordEventWithValue(const char* name, int64_t value) {
RecordEventWithValueAt(name, value, base::TimeTicks::Now());
}
constexpr base::TimeDelta kBitrateReportPeriod = base::Seconds(5);
} // namespace
PlaybackEventsRecorder::BitrateEstimator::BitrateEstimator() {}
PlaybackEventsRecorder::BitrateEstimator::~BitrateEstimator() {}
void PlaybackEventsRecorder::BitrateEstimator::Update(
const PipelineStatistics& stats) {
base::TimeTicks now = base::TimeTicks::Now();
// The code below trusts that |stats| are valid even though they came from an
// untrusted process. That's accepable because the stats are used only to
// record metrics.
if (last_stats_) {
time_elapsed_ += now - last_stats_time_;
audio_bytes_ +=
stats.audio_bytes_decoded - last_stats_->audio_bytes_decoded;
video_bytes_ +=
stats.video_bytes_decoded - last_stats_->video_bytes_decoded;
if (time_elapsed_ >= kBitrateReportPeriod) {
size_t audio_bitrate_kbps =
8 * audio_bytes_ / time_elapsed_.InMilliseconds();
RecordEventWithValueAt("AudioBitrate", audio_bitrate_kbps, now);
size_t video_bitrate_kbps =
8 * video_bytes_ / time_elapsed_.InMilliseconds();
RecordEventWithValueAt("VideoBitrate", video_bitrate_kbps, now);
time_elapsed_ = base::TimeDelta();
audio_bytes_ = 0;
video_bytes_ = 0;
}
}
last_stats_ = stats;
last_stats_time_ = now;
}
void PlaybackEventsRecorder::BitrateEstimator::OnPause() {
last_stats_ = {};
}
// static
void PlaybackEventsRecorder::Create(
mojo::PendingReceiver<mojom::PlaybackEventsRecorder> receiver) {
mojo::MakeSelfOwnedReceiver(std::make_unique<PlaybackEventsRecorder>(),
std::move(receiver));
}
PlaybackEventsRecorder::PlaybackEventsRecorder() = default;
PlaybackEventsRecorder::~PlaybackEventsRecorder() = default;
void PlaybackEventsRecorder::OnPlaying() {
base::RecordComputedAction("WebEngine.Media.Playing");
}
void PlaybackEventsRecorder::OnPaused() {
base::RecordComputedAction("WebEngine.Media.Pause");
bitrate_estimator_.OnPause();
}
void PlaybackEventsRecorder::OnSeeking() {
buffering_state_ = BufferingState::kInitialBuffering;
}
void PlaybackEventsRecorder::OnEnded() {
base::RecordComputedAction("WebEngine.Media.Ended");
}
void PlaybackEventsRecorder::OnBuffering() {
DCHECK(buffering_state_ == BufferingState::kBuffered);
buffering_start_time_ = base::TimeTicks::Now();
buffering_state_ = BufferingState::kBuffering;
bitrate_estimator_.OnPause();
}
void PlaybackEventsRecorder::OnBufferingComplete() {
auto now = base::TimeTicks::Now();
if (buffering_state_ == BufferingState::kBuffering) {
base::TimeDelta time_between_buffering =
buffering_start_time_ - last_buffering_end_time_;
RecordEventWithValueAt("PlayTimeBeforeAutoPause",
time_between_buffering.InMilliseconds(), now);
base::TimeDelta buffering_user_time = now - buffering_start_time_;
RecordEventWithValueAt("AutoPauseTime",
buffering_user_time.InMilliseconds(), now);
}
buffering_state_ = BufferingState::kBuffered;
last_buffering_end_time_ = now;
}
void PlaybackEventsRecorder::OnError(PipelineStatus status) {
RecordEventWithValue("Error", status);
}
void PlaybackEventsRecorder::OnNaturalSizeChanged(const gfx::Size& size) {
int encoded_video_resolution = (size.width() << 16) | size.height();
base::RecordComputedAction(base::StringPrintf(
"WebEngine.Media.VideoResolution:%d", encoded_video_resolution));
}
void PlaybackEventsRecorder::OnPipelineStatistics(
const PipelineStatistics& stats) {
bitrate_estimator_.Update(stats);
}
} // namespace media