blob: 91c9a749986e8d9c3ee7d777ac6cef4c3d0c8859 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/field_trial_params.h"
#include "base/time/time.h"
#include "components/leveldb_proto/public/proto_database.h"
#include "media/base/media_export.h"
#include "media/base/video_codecs.h"
#include "media/capabilities/pending_operations.h"
#include "media/capabilities/webrtc_video_stats_db.h"
#include "ui/gfx/geometry/size.h"
namespace base {
class FilePath;
class Clock;
} // namespace base
namespace leveldb_proto {
class ProtoDatabaseProvider;
} // namespace leveldb_proto
namespace media {
class WebrtcVideoStatsEntryProto;
// LevelDB implementation of WebrtcVideoStatsDB. This class is not
// thread safe. All API calls should happen on the same sequence used for
// construction. API callbacks will also occur on this sequence.
class MEDIA_EXPORT WebrtcVideoStatsDBImpl : public WebrtcVideoStatsDB {
// Create an instance! `db_dir` specifies where to store LevelDB files to
// disk. LevelDB generates a handful of files, so its recommended to provide a
// dedicated directory to keep them isolated.
static std::unique_ptr<WebrtcVideoStatsDBImpl> Create(
base::FilePath db_dir,
leveldb_proto::ProtoDatabaseProvider* db_provider);
~WebrtcVideoStatsDBImpl() override;
WebrtcVideoStatsDBImpl(const WebrtcVideoStatsDBImpl&) = delete;
WebrtcVideoStatsDBImpl& operator=(const WebrtcVideoStatsDBImpl&) = delete;
// Implement WebrtcVideoStatsDB.
void Initialize(InitializeCB init_cb) override;
void AppendVideoStats(const VideoDescKey& key,
const VideoStats& video_stats,
AppendVideoStatsCB append_done_cb) override;
void GetVideoStats(const VideoDescKey& key,
GetVideoStatsCB get_stats_cb) override;
void GetVideoStatsCollection(const VideoDescKey& key,
GetVideoStatsCollectionCB get_stats_cb) override;
void ClearStats(base::OnceClosure clear_done_cb) override;
// Test classes are friends, see comment below.
friend class WebrtcVideoStatsDBImplTest;
friend class WebrtcVideoPerfLPMFuzzerHelper;
// Private constructor only called by tests (friends). Production code
// should always use the static Create() method.
explicit WebrtcVideoStatsDBImpl(
// Called when the database has been initialized. Will immediately call
// `init_cb` to forward `success`.
void OnInit(PendingOperations::Id id,
InitializeCB init_cb,
leveldb_proto::Enums::InitStatus status);
// Returns true if the DB is successfully initialized.
bool IsInitialized();
// Passed as the callback for `OnGotVideoStats` by `AppendVideoStats` to
// update the database once we've read the existing stats entry.
void WriteUpdatedEntry(
PendingOperations::Id op_id,
const VideoDescKey& key,
const VideoStats& new_video_stats,
AppendVideoStatsCB append_done_cb,
bool read_success,
std::unique_ptr<WebrtcVideoStatsEntryProto> stats_proto);
// Called when the database has been modified after a call to
// `WriteUpdatedEntry`. Will run `append_done_cb` when done.
void OnEntryUpdated(PendingOperations::Id op_id,
AppendVideoStatsCB append_done_cb,
bool success);
// Called when GetVideoStats() operation was performed. `get_stats_cb`
// will be run with `success` and a `VideoStatsEntry` created from
// `stats_proto` or nullptr if no entry was found for the requested key.
void OnGotVideoStats(PendingOperations::Id op_id,
GetVideoStatsCB get_stats_cb,
bool success,
std::unique_ptr<WebrtcVideoStatsEntryProto> stats_proto);
// Called when GetVideoStatsCollection() operation was performed.
// `get_stats_cb` will be run with `success` and a `VideoStatsCollection`
// created from the `stats_proto` map or nullptr if no entries were found for
// the filtered key.
void OnGotVideoStatsCollection(
PendingOperations::Id op_id,
GetVideoStatsCollectionCB get_stats_cb,
bool success,
std::unique_ptr<std::map<std::string, WebrtcVideoStatsEntryProto>>
// Internal callback for OnLoadAllKeysForClearing(), initially triggered by
// ClearStats(). Method simply logs `success` and runs `clear_done_cb`.
void OnStatsCleared(PendingOperations::Id op_id,
base::OnceClosure clear_done_cb,
bool success);
// Validates the stats entry. If true is returned the stats are sorted in the
// correct order and contain values that are somewhat reasonable.
bool AreStatsValid(const WebrtcVideoStatsEntryProto* const stats_proto);
void set_wall_clock_for_test(const base::Clock* tick_clock) {
wall_clock_ = tick_clock;
PendingOperations pending_operations_;
// Indicates whether initialization is completed. Does not indicate whether it
// was successful. Will be reset upon calling DestroyStats(). Failed
// initialization is signaled by setting `db_` to null.
bool db_init_ = false;
// ProtoDatabase instance. Set to nullptr if fatal database error is
// encountered. Each entry in the DB is expected to be around 200 bytes. It is
// expected that there will be at most ~100 entries so the total database size
// is expected to not exceed 20 kB.
std::unique_ptr<leveldb_proto::ProtoDatabase<WebrtcVideoStatsEntryProto>> db_;
// For getting wall-clock time. Tests may override via
// set_wall_clock_for_test().
raw_ptr<const base::Clock> wall_clock_ = nullptr;
// Ensures all access to class members come on the same sequence. API calls
// and callbacks should occur on the same sequence used during construction.
// LevelDB operations happen on a separate task runner, but all LevelDB
// callbacks to this happen on the checked sequence.
base::WeakPtrFactory<WebrtcVideoStatsDBImpl> weak_ptr_factory_{this};
} // namespace media