tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

audio_view.h (11302B)


      1 /*
      2 *  Copyright (c) 2024 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #ifndef API_AUDIO_AUDIO_VIEW_H_
     12 #define API_AUDIO_AUDIO_VIEW_H_
     13 
     14 #include <cstddef>
     15 #include <iterator>
     16 #include <variant>
     17 #include <vector>
     18 
     19 #include "api/array_view.h"
     20 #include "rtc_base/checks.h"
     21 
     22 namespace webrtc {
     23 
     24 // This file contains 3 types of view classes:
     25 //
     26 // * MonoView<>: A single channel contiguous buffer of samples.
     27 //
     28 // * InterleavedView<>: Channel samples are interleaved (side-by-side) in
     29 //   the buffer. A single channel InterleavedView<> is the same thing as a
     30 //   MonoView<>
     31 //
     32 // * DeinterleavedView<>: Each channel's samples are contiguous within the
     33 //   buffer. Channels can be enumerated and accessing the individual channel
     34 //   data is done via MonoView<>.
     35 //
     36 // The views are comparable to and built on ArrayView<> but add
     37 // audio specific properties for the dimensions of the buffer and the above
     38 // specialized [de]interleaved support.
     39 //
     40 // There are also a few generic utility functions that can simplify
     41 // generic code for supporting more than one type of view.
     42 
     43 // MonoView<> represents a view over a single contiguous, audio buffer. This
     44 // can be either an single channel (mono) interleaved buffer (e.g. AudioFrame),
     45 // or a de-interleaved channel (e.g. from AudioBuffer).
     46 template <typename T>
     47 using MonoView = ArrayView<T>;
     48 
     49 // The maximum number of audio channels supported by WebRTC encoders, decoders
     50 // and the AudioFrame class.
     51 // TODO(peah, tommi): Should kMaxNumberOfAudioChannels be 16 rather than 24?
     52 // The reason is that AudioFrame's max number of samples is 7680, which can
     53 // hold 16 10ms 16bit channels at 48 kHz (and not 24 channels).
     54 static constexpr size_t kMaxNumberOfAudioChannels = 24;
     55 
     56 // InterleavedView<> is a view over an interleaved audio buffer (e.g. from
     57 // AudioFrame).
     58 template <typename T>
     59 class InterleavedView {
     60 public:
     61  using value_type = T;
     62 
     63  InterleavedView() = default;
     64 
     65  template <typename U>
     66  InterleavedView(U* data, size_t samples_per_channel, size_t num_channels)
     67      : num_channels_(num_channels),
     68        samples_per_channel_(samples_per_channel),
     69        data_(data, num_channels * samples_per_channel) {
     70    RTC_DCHECK_LE(num_channels_, kMaxNumberOfAudioChannels);
     71    RTC_DCHECK(num_channels_ == 0u || samples_per_channel_ != 0u);
     72  }
     73 
     74  // Construct an InterleavedView from a C-style array. Samples per channels
     75  // is calculated based on the array size / num_channels.
     76  template <typename U, size_t N>
     77  InterleavedView(U (&array)[N],  // NOLINT
     78                  size_t num_channels)
     79      : InterleavedView(array, N / num_channels, num_channels) {
     80    RTC_DCHECK_EQ(N % num_channels, 0u);
     81  }
     82 
     83  template <typename U>
     84  InterleavedView(const InterleavedView<U>& other)
     85      : num_channels_(other.num_channels()),
     86        samples_per_channel_(other.samples_per_channel()),
     87        data_(other.data()) {}
     88 
     89  size_t num_channels() const { return num_channels_; }
     90  size_t samples_per_channel() const { return samples_per_channel_; }
     91  ArrayView<T> data() const { return data_; }
     92  bool empty() const { return data_.empty(); }
     93  size_t size() const { return data_.size(); }
     94 
     95  MonoView<T> AsMono() const {
     96    RTC_DCHECK_EQ(num_channels(), 1u);
     97    RTC_DCHECK_EQ(data_.size(), samples_per_channel_);
     98    return data_;
     99  }
    100 
    101  // A simple wrapper around memcpy that includes checks for properties.
    102  // TODO(tommi): Consider if this can be utility function for both interleaved
    103  // and deinterleaved views.
    104  template <typename U>
    105  void CopyFrom(const InterleavedView<U>& source) {
    106    static_assert(sizeof(T) == sizeof(U), "");
    107    RTC_DCHECK_EQ(num_channels(), source.num_channels());
    108    RTC_DCHECK_EQ(samples_per_channel(), source.samples_per_channel());
    109    RTC_DCHECK_GE(data_.size(), source.data().size());
    110    const auto data = source.data();
    111    memcpy(&data_[0], &data[0], data.size() * sizeof(U));
    112  }
    113 
    114  T& operator[](size_t idx) const { return data_[idx]; }
    115  T* begin() const { return data_.begin(); }
    116  T* end() const { return data_.end(); }
    117  const T* cbegin() const { return data_.cbegin(); }
    118  const T* cend() const { return data_.cend(); }
    119  std::reverse_iterator<T*> rbegin() const { return data_.rbegin(); }
    120  std::reverse_iterator<T*> rend() const { return data_.rend(); }
    121  std::reverse_iterator<const T*> crbegin() const { return data_.crbegin(); }
    122  std::reverse_iterator<const T*> crend() const { return data_.crend(); }
    123 
    124 private:
    125  // TODO(tommi): Consider having these both be stored as uint16_t to
    126  // save a few bytes per view. Use `dchecked_cast` to support size_t during
    127  // construction.
    128  size_t num_channels_ = 0u;
    129  size_t samples_per_channel_ = 0u;
    130  ArrayView<T> data_;
    131 };
    132 
    133 template <typename T>
    134 class DeinterleavedView {
    135 public:
    136  using value_type = T;
    137 
    138  DeinterleavedView() = default;
    139 
    140  // Construct a view where all the channels are coallocated in a single buffer.
    141  template <typename U>
    142  DeinterleavedView(U* data, size_t samples_per_channel, size_t num_channels)
    143      : num_channels_(num_channels),
    144        samples_per_channel_(samples_per_channel),
    145        data_(data) {}
    146 
    147  // Construct a view from an array of channel pointers where the channels
    148  // may all be allocated seperately.
    149  template <typename U>
    150  DeinterleavedView(U* const* channels,
    151                    size_t samples_per_channel,
    152                    size_t num_channels)
    153      : num_channels_(num_channels),
    154        samples_per_channel_(samples_per_channel),
    155        data_(channels) {}
    156 
    157  // Construct a view from an array of channel pointers where the pointers are
    158  // helt in a `std::vector<>`.
    159  template <typename U>
    160  DeinterleavedView(const std::vector<U*>& channels, size_t samples_per_channel)
    161      : num_channels_(channels.size()),
    162        samples_per_channel_(samples_per_channel),
    163        data_(channels.data()) {}
    164 
    165  // Construct a view from another view. Note that the type of
    166  // the other view may be different from the current type and
    167  // therefore the internal data types may not be exactly the
    168  // same, but still compatible.
    169  // E.g.:
    170  // DeinterleavedView<float> mutable_view;
    171  // DeinterleavedView<const float> const_view(mutable_view);
    172  template <typename U>
    173  DeinterleavedView(const DeinterleavedView<U>& other)
    174      : num_channels_(other.num_channels_),
    175        samples_per_channel_(other.samples_per_channel()) {
    176    if (other.is_ptr_array()) {
    177      data_ = std::get<U* const*>(other.data_);
    178    } else {
    179      data_ = std::get<U*>(other.data_);
    180    }
    181  }
    182 
    183  // Returns a deinterleaved channel where `idx` is the zero based index,
    184  // in the range [0 .. num_channels()-1].
    185  MonoView<T> operator[](size_t idx) const {
    186    RTC_DCHECK_LT(idx, num_channels());
    187    if (is_ptr_array())
    188      return MonoView<T>(std::get<T* const*>(data_)[idx], samples_per_channel_);
    189    return MonoView<T>(&std::get<T*>(data_)[idx * samples_per_channel_],
    190                       samples_per_channel_);
    191  }
    192 
    193  size_t num_channels() const { return num_channels_; }
    194  size_t samples_per_channel() const { return samples_per_channel_; }
    195  bool empty() const {
    196    return num_channels_ == 0u || samples_per_channel_ == 0u;
    197  }
    198  size_t size() const { return num_channels_ * samples_per_channel_; }
    199 
    200  // Returns the first (and possibly only) channel.
    201  MonoView<T> AsMono() const {
    202    RTC_DCHECK_GE(num_channels(), 1u);
    203    return (*this)[0];
    204  }
    205 
    206  // Zeros out all samples in channels represented by the view.
    207  void Clear() {
    208    for (size_t i = 0u; i < num_channels_; ++i) {
    209      MonoView<T> view = (*this)[i];
    210      ClearSamples(view);
    211    }
    212  }
    213 
    214 private:
    215  bool is_ptr_array() const { return std::holds_alternative<T* const*>(data_); }
    216 
    217  template <typename U>
    218  friend class DeinterleavedView;
    219 
    220  size_t num_channels_ = 0u;
    221  size_t samples_per_channel_ = 0u;
    222  std::variant<T* const*, T*> data_;
    223 };
    224 
    225 template <typename T>
    226 constexpr size_t NumChannels(const MonoView<T>& /* view */) {
    227  return 1u;
    228 }
    229 
    230 template <typename T>
    231 size_t NumChannels(const InterleavedView<T>& view) {
    232  return view.num_channels();
    233 }
    234 
    235 template <typename T>
    236 size_t NumChannels(const DeinterleavedView<T>& view) {
    237  return view.num_channels();
    238 }
    239 
    240 template <typename T>
    241 constexpr bool IsMono(const MonoView<T>& /* view */) {
    242  return true;
    243 }
    244 
    245 template <typename T>
    246 constexpr bool IsInterleavedView(const MonoView<T>& /* view */) {
    247  return true;
    248 }
    249 
    250 template <typename T>
    251 constexpr bool IsInterleavedView(const InterleavedView<T>& /* view */) {
    252  return true;
    253 }
    254 
    255 template <typename T>
    256 constexpr bool IsInterleavedView(const DeinterleavedView<const T>& /* view */) {
    257  return false;
    258 }
    259 
    260 template <typename T>
    261 bool IsMono(const InterleavedView<T>& view) {
    262  return NumChannels(view) == 1u;
    263 }
    264 
    265 template <typename T>
    266 bool IsMono(const DeinterleavedView<T>& view) {
    267  return NumChannels(view) == 1u;
    268 }
    269 
    270 template <typename T>
    271 size_t SamplesPerChannel(const MonoView<T>& view) {
    272  return view.size();
    273 }
    274 
    275 template <typename T>
    276 size_t SamplesPerChannel(const InterleavedView<T>& view) {
    277  return view.samples_per_channel();
    278 }
    279 
    280 template <typename T>
    281 size_t SamplesPerChannel(const DeinterleavedView<T>& view) {
    282  return view.samples_per_channel();
    283 }
    284 // A simple wrapper around memcpy that includes checks for properties.
    285 // The parameter order is the same as for memcpy(), first destination then
    286 // source.
    287 template <typename D, typename S>
    288 void CopySamples(D& destination, const S& source) {
    289  static_assert(
    290      sizeof(typename D::value_type) == sizeof(typename S::value_type), "");
    291  // Here we'd really like to do
    292  // static_assert(IsInterleavedView(destination) == IsInterleavedView(source),
    293  //               "");
    294  // but the compiler doesn't like it inside this template function for
    295  // some reason. The following check is an approximation but unfortunately
    296  // means that copying between a MonoView and single channel interleaved or
    297  // deinterleaved views wouldn't work.
    298  // static_assert(sizeof(destination) == sizeof(source),
    299  //               "Incompatible view types");
    300  RTC_DCHECK_EQ(NumChannels(destination), NumChannels(source));
    301  RTC_DCHECK_EQ(SamplesPerChannel(destination), SamplesPerChannel(source));
    302  RTC_DCHECK_GE(destination.size(), source.size());
    303  memcpy(&destination[0], &source[0],
    304         source.size() * sizeof(typename S::value_type));
    305 }
    306 
    307 // Sets all the samples in a view to 0. This template function is a simple
    308 // wrapper around `memset()` but adds the benefit of automatically calculating
    309 // the byte size from the number of samples and sample type.
    310 template <typename T>
    311 void ClearSamples(T& view) {
    312  memset(&view[0], 0, view.size() * sizeof(typename T::value_type));
    313 }
    314 
    315 // Same as `ClearSamples()` above but allows for clearing only the first
    316 // `sample_count` number of samples.
    317 template <typename T>
    318 void ClearSamples(T& view, size_t sample_count) {
    319  RTC_DCHECK_LE(sample_count, view.size());
    320  memset(&view[0], 0, sample_count * sizeof(typename T::value_type));
    321 }
    322 
    323 }  // namespace webrtc
    324 
    325 #endif  // API_AUDIO_AUDIO_VIEW_H_