chromium/chromecast/media/audio/interleaved_channel_mixer_unittest.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromecast/media/audio/interleaved_channel_mixer.h"

#include <cmath>
#include <string>
#include <tuple>

#include "media/base/audio_bus.h"
#include "media/base/audio_sample_types.h"
#include "media/base/channel_layout.h"
#include "media/base/channel_mixer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace chromecast {
namespace media {

namespace {
const int kNumFrames = 32;
}  // namespace

using TestParams = std::tuple<::media::ChannelLayout /* input layout */,
                              ::media::ChannelLayout /* output layout */>;

class InterleavedChannelMixerTest : public testing::TestWithParam<TestParams> {
 public:
  InterleavedChannelMixerTest() = default;

  InterleavedChannelMixerTest(const InterleavedChannelMixerTest&) = delete;
  InterleavedChannelMixerTest& operator=(const InterleavedChannelMixerTest&) =
      delete;

  ~InterleavedChannelMixerTest() override = default;
};

TEST_P(InterleavedChannelMixerTest, Transform) {
  const TestParams& params = GetParam();
  const ::media::ChannelLayout input_layout = testing::get<0>(params);
  const ::media::ChannelLayout output_layout = testing::get<1>(params);
  const int num_input_channels =
      ::media::ChannelLayoutToChannelCount(input_layout);
  const int num_output_channels =
      ::media::ChannelLayoutToChannelCount(output_layout);

  auto original = ::media::AudioBus::Create(num_input_channels, kNumFrames);
  for (int c = 0; c < num_input_channels; ++c) {
    for (int f = 0; f < kNumFrames; ++f) {
      original->channel(c)[f] = std::pow(-1, f + c) * 0.01 +
                                c / static_cast<float>(num_input_channels * 10);
    }
  }

  auto transformed = ::media::AudioBus::Create(num_output_channels, kNumFrames);
  transformed->Zero();

  // Check that the output of upstream ChannelMixer + interleave is the same
  // as the output of interleave + InterleavedChannelMixer.
  ::media::ChannelMixer channel_mixer(
      input_layout, ::media::ChannelLayoutToChannelCount(input_layout),
      output_layout, ::media::ChannelLayoutToChannelCount(output_layout));
  channel_mixer.Transform(original.get(), transformed.get());

  std::vector<float> original_interleaved(num_input_channels * kNumFrames);
  original->ToInterleaved<::media::Float32SampleTypeTraits>(
      kNumFrames, original_interleaved.data());

  InterleavedChannelMixer interleaved_mixer(input_layout, num_input_channels,
                                            output_layout, num_output_channels,
                                            kNumFrames);
  float* interleaved_mixed =
      interleaved_mixer.Transform(original_interleaved.data(), kNumFrames);

  std::vector<float> transformed_interleaved(num_output_channels * kNumFrames);
  transformed->ToInterleaved<::media::Float32SampleTypeTraits>(
      kNumFrames, transformed_interleaved.data());

  for (int f = 0; f < kNumFrames; ++f) {
    for (int c = 0; c < num_output_channels; ++c) {
      EXPECT_FLOAT_EQ(interleaved_mixed[f * num_output_channels + c],
                      transformed_interleaved[f * num_output_channels + c])
          << "at frame " << f << ", channel " << c;
    }
  }
}

INSTANTIATE_TEST_SUITE_P(
    CommonLayouts,
    InterleavedChannelMixerTest,
    testing::Combine(
        ::testing::Values(::media::ChannelLayout::CHANNEL_LAYOUT_MONO,
                          ::media::ChannelLayout::CHANNEL_LAYOUT_STEREO,
                          ::media::ChannelLayout::CHANNEL_LAYOUT_5_1),
        ::testing::Values(::media::ChannelLayout::CHANNEL_LAYOUT_MONO,
                          ::media::ChannelLayout::CHANNEL_LAYOUT_STEREO,
                          ::media::ChannelLayout::CHANNEL_LAYOUT_5_1)));

}  // namespace media
}  // namespace chromecast