tor-browser

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

TestAudioTrackEncoder.cpp (10399B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "AudioGenerator.h"
      8 #include "AudioSampleFormat.h"
      9 #include "OpusTrackEncoder.h"
     10 #include "gtest/gtest.h"
     11 
     12 using namespace mozilla;
     13 
     14 class TestOpusTrackEncoder : public OpusTrackEncoder {
     15 public:
     16  TestOpusTrackEncoder(TrackRate aTrackRate,
     17                       MediaQueue<EncodedFrame>& aEncodedDataQueue)
     18      : OpusTrackEncoder(aTrackRate, aEncodedDataQueue) {}
     19 
     20  // Return true if it has successfully initialized the Opus encoder.
     21  bool TestOpusRawCreation(int aChannels) {
     22    if (Init(aChannels) == NS_OK) {
     23      if (IsInitialized()) {
     24        return true;
     25      }
     26    }
     27    return false;
     28  }
     29 };
     30 
     31 static bool TestOpusInit(int aChannels, TrackRate aSamplingRate) {
     32  MediaQueue<EncodedFrame> frames;
     33  TestOpusTrackEncoder encoder(aSamplingRate, frames);
     34  return encoder.TestOpusRawCreation(aChannels);
     35 }
     36 
     37 TEST(OpusAudioTrackEncoder, InitRaw)
     38 {
     39  // Expect false with 0 or negative channels of input signal.
     40  EXPECT_FALSE(TestOpusInit(0, 16000));
     41  EXPECT_FALSE(TestOpusInit(-1, 16000));
     42 
     43  // The Opus format supports up to 8 channels, and supports multitrack audio up
     44  // to 255 channels, but the current implementation supports only mono and
     45  // stereo, and downmixes any more than that.
     46  // Expect false with channels of input signal exceed the max supported number.
     47  EXPECT_FALSE(TestOpusInit(8 + 1, 16000));
     48 
     49  // Should accept channels within valid range.
     50  for (int i = 1; i <= 8; i++) {
     51    EXPECT_TRUE(TestOpusInit(i, 16000));
     52  }
     53 
     54  // Expect false with 0 or negative sampling rate of input signal.
     55  EXPECT_FALSE(TestOpusInit(1, 0));
     56  EXPECT_FALSE(TestOpusInit(1, -1));
     57 
     58  // Verify sample rate bounds checking.
     59  EXPECT_FALSE(TestOpusInit(2, 2000));
     60  EXPECT_FALSE(TestOpusInit(2, 4000));
     61  EXPECT_FALSE(TestOpusInit(2, 7999));
     62  EXPECT_TRUE(TestOpusInit(2, 8000));
     63  EXPECT_TRUE(TestOpusInit(2, 192000));
     64  EXPECT_FALSE(TestOpusInit(2, 192001));
     65  EXPECT_FALSE(TestOpusInit(2, 200000));
     66 }
     67 
     68 TEST(OpusAudioTrackEncoder, Init)
     69 {
     70  {
     71    // The encoder does not normally recieve enough info from null data to
     72    // init. However, multiple attempts to do so, with sufficiently long
     73    // duration segments, should result in a default-init. The first attempt
     74    // should never do this though, even if the duration is long:
     75    MediaQueue<EncodedFrame> frames;
     76    OpusTrackEncoder encoder(48000, frames);
     77    AudioSegment segment;
     78    segment.AppendNullData(48000 * 100);
     79    encoder.TryInit(segment, segment.GetDuration());
     80    EXPECT_FALSE(encoder.IsInitialized());
     81 
     82    // Multiple init attempts should result in best effort init:
     83    encoder.TryInit(segment, segment.GetDuration());
     84    EXPECT_TRUE(encoder.IsInitialized());
     85  }
     86 
     87  {
     88    // For non-null segments we should init immediately
     89    MediaQueue<EncodedFrame> frames;
     90    OpusTrackEncoder encoder(48000, frames);
     91    AudioSegment segment;
     92    AudioGenerator<AudioDataValue> generator(2, 48000);
     93    generator.Generate(segment, 1);
     94    encoder.TryInit(segment, segment.GetDuration());
     95    EXPECT_TRUE(encoder.IsInitialized());
     96  }
     97 
     98  {
     99    // Test low sample rate bound
    100    MediaQueue<EncodedFrame> frames;
    101    OpusTrackEncoder encoder(7999, frames);
    102    AudioSegment segment;
    103    AudioGenerator<AudioDataValue> generator(2, 7999);
    104    generator.Generate(segment, 1);
    105    encoder.TryInit(segment, segment.GetDuration());
    106    EXPECT_FALSE(encoder.IsInitialized());
    107  }
    108 
    109  {
    110    // Test low sample rate bound
    111    MediaQueue<EncodedFrame> frames;
    112    OpusTrackEncoder encoder(8000, frames);
    113    AudioSegment segment;
    114    AudioGenerator<AudioDataValue> generator(2, 8000);
    115    generator.Generate(segment, 1);
    116    encoder.TryInit(segment, segment.GetDuration());
    117    EXPECT_TRUE(encoder.IsInitialized());
    118  }
    119 
    120  {
    121    // Test high sample rate bound
    122    MediaQueue<EncodedFrame> frames;
    123    OpusTrackEncoder encoder(192001, frames);
    124    AudioSegment segment;
    125    AudioGenerator<AudioDataValue> generator(2, 192001);
    126    generator.Generate(segment, 1);
    127    encoder.TryInit(segment, segment.GetDuration());
    128    EXPECT_FALSE(encoder.IsInitialized());
    129  }
    130 
    131  {
    132    // Test high sample rate bound
    133    MediaQueue<EncodedFrame> frames;
    134    OpusTrackEncoder encoder(192000, frames);
    135    AudioSegment segment;
    136    AudioGenerator<AudioDataValue> generator(2, 192000);
    137    generator.Generate(segment, 1);
    138    encoder.TryInit(segment, segment.GetDuration());
    139    EXPECT_TRUE(encoder.IsInitialized());
    140  }
    141 
    142  {
    143    // Test that it takes 10s to trigger default-init.
    144    MediaQueue<EncodedFrame> frames;
    145    OpusTrackEncoder encoder(48000, frames);
    146    AudioSegment longSegment;
    147    longSegment.AppendNullData(48000 * 10 - 1);
    148    AudioSegment shortSegment;
    149    shortSegment.AppendNullData(1);
    150    encoder.TryInit(longSegment, longSegment.GetDuration());
    151    EXPECT_FALSE(encoder.IsInitialized());
    152    encoder.TryInit(shortSegment, shortSegment.GetDuration());
    153    EXPECT_FALSE(encoder.IsInitialized());
    154    encoder.TryInit(shortSegment, shortSegment.GetDuration());
    155    EXPECT_TRUE(encoder.IsInitialized());
    156  }
    157 }
    158 
    159 static int TestOpusResampler(TrackRate aSamplingRate) {
    160  MediaQueue<EncodedFrame> frames;
    161  OpusTrackEncoder encoder(aSamplingRate, frames);
    162  return encoder.mOutputSampleRate;
    163 }
    164 
    165 TEST(OpusAudioTrackEncoder, Resample)
    166 {
    167  // Sampling rates of data to be fed to Opus encoder, should remain unchanged
    168  // if it is one of Opus supported rates (8000, 12000, 16000, 24000 and 48000
    169  // (kHz)) at initialization.
    170  EXPECT_TRUE(TestOpusResampler(8000) == 8000);
    171  EXPECT_TRUE(TestOpusResampler(12000) == 12000);
    172  EXPECT_TRUE(TestOpusResampler(16000) == 16000);
    173  EXPECT_TRUE(TestOpusResampler(24000) == 24000);
    174  EXPECT_TRUE(TestOpusResampler(48000) == 48000);
    175 
    176  // Otherwise, it should be resampled to 48kHz by resampler.
    177  EXPECT_TRUE(TestOpusResampler(9600) == 48000);
    178  EXPECT_TRUE(TestOpusResampler(44100) == 48000);
    179 }
    180 
    181 TEST(OpusAudioTrackEncoder, FetchMetadata)
    182 {
    183  const int32_t channels = 1;
    184  const TrackRate sampleRate = 44100;
    185  MediaQueue<EncodedFrame> frames;
    186  TestOpusTrackEncoder encoder(sampleRate, frames);
    187  EXPECT_TRUE(encoder.TestOpusRawCreation(channels));
    188 
    189  RefPtr<TrackMetadataBase> metadata = encoder.GetMetadata();
    190  ASSERT_EQ(TrackMetadataBase::METADATA_OPUS, metadata->GetKind());
    191 
    192  RefPtr<OpusMetadata> opusMeta = static_cast<OpusMetadata*>(metadata.get());
    193  EXPECT_EQ(channels, opusMeta->mChannels);
    194  EXPECT_EQ(sampleRate, opusMeta->mSamplingFrequency);
    195 }
    196 
    197 TEST(OpusAudioTrackEncoder, FrameEncode)
    198 {
    199  const int32_t channels = 1;
    200  const TrackRate sampleRate = 44100;
    201  MediaQueue<EncodedFrame> frames;
    202  TestOpusTrackEncoder encoder(sampleRate, frames);
    203  EXPECT_TRUE(encoder.TestOpusRawCreation(channels));
    204 
    205  // Generate five seconds of raw audio data.
    206  AudioGenerator<AudioDataValue> generator(channels, sampleRate);
    207  AudioSegment segment;
    208  const int32_t samples = sampleRate * 5;
    209  generator.Generate(segment, samples);
    210 
    211  encoder.AppendAudioSegment(std::move(segment));
    212  encoder.NotifyEndOfStream();
    213 
    214  EXPECT_TRUE(encoder.IsEncodingComplete());
    215  EXPECT_TRUE(frames.IsFinished());
    216 
    217  // Verify that encoded data is 5 seconds long.
    218  uint64_t totalDuration = 0;
    219  while (RefPtr<EncodedFrame> frame = frames.PopFront()) {
    220    totalDuration += frame->mDuration;
    221  }
    222  // 44100 as used above gets resampled to 48000 for opus.
    223  const uint64_t five = 48000 * 5;
    224  EXPECT_EQ(five + encoder.GetLookahead(), totalDuration);
    225 }
    226 
    227 TEST(OpusAudioTrackEncoder, DefaultInitDuration)
    228 {
    229  const TrackRate rate = 44100;
    230  MediaQueue<EncodedFrame> frames;
    231  OpusTrackEncoder encoder(rate, frames);
    232  AudioGenerator<AudioDataValue> generator(2, rate);
    233  AudioSegment segment;
    234  // 15 seconds should trigger the default-init rate.
    235  // The default-init timeout is evaluated once per chunk, so keep chunks
    236  // reasonably short.
    237  for (int i = 0; i < 150; ++i) {
    238    generator.Generate(segment, rate / 10);
    239  }
    240  encoder.AppendAudioSegment(std::move(segment));
    241  encoder.NotifyEndOfStream();
    242 
    243  EXPECT_TRUE(encoder.IsEncodingComplete());
    244  EXPECT_TRUE(frames.IsFinished());
    245 
    246  // Verify that encoded data is 15 seconds long.
    247  uint64_t totalDuration = 0;
    248  while (RefPtr<EncodedFrame> frame = frames.PopFront()) {
    249    totalDuration += frame->mDuration;
    250  }
    251  // 44100 as used above gets resampled to 48000 for opus.
    252  const uint64_t fifteen = 48000 * 15;
    253  EXPECT_EQ(totalDuration, fifteen + encoder.GetLookahead());
    254 }
    255 
    256 uint64_t TestSampleRate(TrackRate aSampleRate, uint64_t aInputFrames) {
    257  MediaQueue<EncodedFrame> frames;
    258  OpusTrackEncoder encoder(aSampleRate, frames);
    259  AudioGenerator<AudioDataValue> generator(2, aSampleRate);
    260  AudioSegment segment;
    261  const uint64_t chunkSize = aSampleRate / 10;
    262  const uint64_t chunks = aInputFrames / chunkSize;
    263  // 15 seconds should trigger the default-init rate.
    264  // The default-init timeout is evaluated once per chunk, so keep chunks
    265  // reasonably short.
    266  for (size_t i = 0; i < chunks; ++i) {
    267    generator.Generate(segment, chunkSize);
    268  }
    269  generator.Generate(segment, aInputFrames % chunks);
    270  encoder.AppendAudioSegment(std::move(segment));
    271  encoder.NotifyEndOfStream();
    272 
    273  EXPECT_TRUE(encoder.IsEncodingComplete());
    274  EXPECT_TRUE(frames.IsFinished());
    275 
    276  // Verify that encoded data is 15 seconds long.
    277  uint64_t totalDuration = 0;
    278  while (RefPtr<EncodedFrame> frame = frames.PopFront()) {
    279    totalDuration += frame->mDuration;
    280  }
    281  return totalDuration - encoder.GetLookahead();
    282 }
    283 
    284 TEST(OpusAudioTrackEncoder, DurationSampleRates)
    285 {
    286  // Factors of 48k
    287  EXPECT_EQ(TestSampleRate(48000, 48000 * 3 / 2), 48000U * 3 / 2);
    288  EXPECT_EQ(TestSampleRate(24000, 24000 * 3 / 2), 48000U * 3 / 2);
    289  EXPECT_EQ(TestSampleRate(16000, 16000 * 3 / 2), 48000U * 3 / 2);
    290  EXPECT_EQ(TestSampleRate(12000, 12000 * 3 / 2), 48000U * 3 / 2);
    291  EXPECT_EQ(TestSampleRate(8000, 8000 * 3 / 2), 48000U * 3 / 2);
    292 
    293  // Non-factors of 48k, resampled
    294  EXPECT_EQ(TestSampleRate(44100, 44100 * 3 / 2), 48000U * 3 / 2);
    295  EXPECT_EQ(TestSampleRate(32000, 32000 * 3 / 2), 48000U * 3 / 2);
    296  EXPECT_EQ(TestSampleRate(96000, 96000 * 3 / 2), 48000U * 3 / 2);
    297  EXPECT_EQ(TestSampleRate(33330, 33330 * 3 / 2), 48000U * 3 / 2);
    298 }