| // Copyright 2023 The Cobalt Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/media/base/metrics_provider.h" |
| |
| #include "base/logging.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/time/time.h" |
| |
| namespace cobalt { |
| namespace media { |
| |
| using starboard::ScopedLock; |
| |
| MediaMetricsProvider::~MediaMetricsProvider() { ReportPipelineUMA(); } |
| |
| void MediaMetricsProvider::OnError(const ::media::PipelineStatus status) { |
| ScopedLock scoped_lock(mutex_); |
| uma_info_.last_pipeline_status = status; |
| } |
| |
| void MediaMetricsProvider::SetHasAudio(AudioCodec audio_codec) { |
| ScopedLock scoped_lock(mutex_); |
| uma_info_.audio_codec = audio_codec; |
| uma_info_.has_audio = true; |
| } |
| |
| void MediaMetricsProvider::SetHasVideo(VideoCodec video_codec) { |
| ScopedLock scoped_lock(mutex_); |
| uma_info_.video_codec = video_codec; |
| uma_info_.has_video = true; |
| } |
| |
| void MediaMetricsProvider::SetHasPlayed() { |
| ScopedLock scoped_lock(mutex_); |
| uma_info_.has_ever_played = true; |
| } |
| |
| void MediaMetricsProvider::SetHaveEnough() { |
| ScopedLock scoped_lock(mutex_); |
| uma_info_.has_reached_have_enough = true; |
| } |
| |
| void MediaMetricsProvider::SetIsEME() { |
| ScopedLock scoped_lock(mutex_); |
| uma_info_.is_eme = true; |
| } |
| |
| void MediaMetricsProvider::ReportPipelineUMA() { |
| ScopedLock scoped_lock(mutex_); |
| if (uma_info_.has_video && uma_info_.has_audio) { |
| base::UmaHistogramExactLinear(GetUMANameForAVStream(uma_info_), |
| uma_info_.last_pipeline_status, |
| PipelineStatus::PIPELINE_STATUS_MAX + 1); |
| } else if (uma_info_.has_audio) { |
| base::UmaHistogramExactLinear("Cobalt.Media.PipelineStatus.AudioOnly", |
| uma_info_.last_pipeline_status, |
| PipelineStatus::PIPELINE_STATUS_MAX + 1); |
| } else if (uma_info_.has_video) { |
| base::UmaHistogramExactLinear("Cobalt.Media.PipelineStatus.VideoOnly", |
| uma_info_.last_pipeline_status, |
| PipelineStatus::PIPELINE_STATUS_MAX + 1); |
| } else { |
| // Note: This metric can be recorded as a result of normal operation with |
| // Media Source Extensions. If a site creates a MediaSource object but never |
| // creates a source buffer or appends data, PIPELINE_OK will be recorded. |
| base::UmaHistogramExactLinear("Cobalt.Media.PipelineStatus.Unsupported", |
| uma_info_.last_pipeline_status, |
| PipelineStatus::PIPELINE_STATUS_MAX + 1); |
| } |
| |
| // Report whether this player ever saw a playback event. Used to measure the |
| // effectiveness of efforts to reduce loaded-but-never-used players. |
| if (uma_info_.has_reached_have_enough) |
| base::UmaHistogramBoolean("Cobalt.Media.HasEverPlayed", |
| uma_info_.has_ever_played); |
| } |
| |
| std::string MediaMetricsProvider::GetUMANameForAVStream( |
| const PipelineInfo& player_info) const { |
| constexpr char kPipelineUmaPrefix[] = |
| "Cobalt.Media.PipelineStatus.AudioVideo."; |
| std::string uma_name = kPipelineUmaPrefix; |
| if (player_info.video_codec == VideoCodec::kVP9) |
| uma_name += "VP9"; |
| else if (player_info.video_codec == VideoCodec::kH264) |
| uma_name += "H264"; |
| else if (player_info.video_codec == VideoCodec::kAV1) |
| uma_name += "AV1"; |
| else |
| uma_name += "Other"; |
| |
| return uma_name; |
| } |
| |
| void MediaMetricsProvider::StartTrackingAction(MediaAction action) { |
| DCHECK(!IsActionCurrentlyTracked(action)); |
| ScopedLock scoped_lock(mutex_); |
| |
| tracked_actions_start_times_[action] = clock_->NowTicks(); |
| } |
| |
| void MediaMetricsProvider::EndTrackingAction(MediaAction action) { |
| DCHECK(IsActionCurrentlyTracked(action)); |
| ScopedLock scoped_lock(mutex_); |
| |
| auto duration = clock_->NowTicks() - tracked_actions_start_times_[action]; |
| ReportActionLatencyUMA(action, duration); |
| tracked_actions_start_times_.erase(action); |
| } |
| |
| bool MediaMetricsProvider::IsActionCurrentlyTracked(MediaAction action) { |
| ScopedLock scoped_lock(mutex_); |
| return tracked_actions_start_times_.find(action) != |
| tracked_actions_start_times_.end(); |
| } |
| |
| void MediaMetricsProvider::ReportActionLatencyUMA( |
| MediaAction action, const base::TimeDelta& action_duration) { |
| switch (action) { |
| case MediaAction::WEBMEDIAPLAYER_SEEK: |
| UMA_HISTOGRAM_TIMES("Cobalt.Media.WebMediaPlayer.Seek.Timing", |
| action_duration); |
| break; |
| case MediaAction::SBPLAYER_CREATE: |
| UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( |
| "Cobalt.Media.SbPlayer.Create.Timing", action_duration, |
| base::TimeDelta::FromMicroseconds(100), |
| base::TimeDelta::FromMicroseconds(1500), 50); |
| break; |
| case MediaAction::SBPLAYER_CREATE_URL_PLAYER: |
| UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( |
| "Cobalt.Media.SbPlayer.CreateUrlPlayer.Timing", action_duration, |
| base::TimeDelta::FromMicroseconds(100), |
| base::TimeDelta::FromMicroseconds(1500), 50); |
| break; |
| case MediaAction::SBPLAYER_DESTROY: |
| UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( |
| "Cobalt.Media.SbPlayer.Destroy.Timing", action_duration, |
| base::TimeDelta::FromMicroseconds(500), |
| base::TimeDelta::FromMicroseconds(40000), 50); |
| break; |
| case MediaAction::UNKNOWN_ACTION: |
| default: |
| break; |
| } |
| } |
| |
| } // namespace media |
| } // namespace cobalt |