1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159

media / capabilities / webrtc_video_stats_db_impl.h [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.

#ifndef MEDIA_CAPABILITIES_WEBRTC_VIDEO_STATS_DB_IMPL_H_
#define MEDIA_CAPABILITIES_WEBRTC_VIDEO_STATS_DB_IMPL_H_

#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 {
 public:
  // 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;

 private:
  // 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(
      std::unique_ptr<leveldb_proto::ProtoDatabase<WebrtcVideoStatsEntryProto>>
          db);

  // 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>>
          stats_proto);

  // 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.
  SEQUENCE_CHECKER(sequence_checker_);

  base::WeakPtrFactory<WebrtcVideoStatsDBImpl> weak_ptr_factory_{this};
};

}  // namespace media

#endif  // MEDIA_CAPABILITIES_WEBRTC_VIDEO_STATS_DB_IMPL_H_