summaryrefslogtreecommitdiffstats
path: root/media/base/channel_mixer_unittest.cc
blob: a71f86bb5422de349a69d7bc9b857ed5c255d0e4 (plain)
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
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// MSVC++ requires this to be set before any other includes to get M_SQRT1_2.
#define _USE_MATH_DEFINES

#include <cmath>

#include "base/stringprintf.h"
#include "media/base/audio_bus.h"
#include "media/base/channel_mixer.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {

// Number of frames to test with.
enum { kFrames = 16 };

// Test all possible layout conversions can be constructed and mixed.
TEST(ChannelMixerTest, ConstructAllPossibleLayouts) {
  for (ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
       input_layout < CHANNEL_LAYOUT_MAX;
       input_layout = static_cast<ChannelLayout>(input_layout + 1)) {
    for (ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
         output_layout < CHANNEL_LAYOUT_STEREO_DOWNMIX;
         output_layout = static_cast<ChannelLayout>(output_layout + 1)) {
      SCOPED_TRACE(base::StringPrintf(
          "Input Layout: %d, Output Layout: %d", input_layout, output_layout));
      ChannelMixer mixer(input_layout, output_layout);
      scoped_ptr<AudioBus> input_bus = AudioBus::Create(
          ChannelLayoutToChannelCount(input_layout), kFrames);
      scoped_ptr<AudioBus> output_bus = AudioBus::Create(
          ChannelLayoutToChannelCount(output_layout), kFrames);
      for (int ch = 0; ch < input_bus->channels(); ++ch)
        std::fill(input_bus->channel(ch), input_bus->channel(ch) + kFrames, 1);

      mixer.Transform(input_bus.get(), output_bus.get());
    }
  }
}

struct ChannelMixerTestData {
  ChannelMixerTestData(ChannelLayout input_layout, ChannelLayout output_layout,
                       float* channel_values, int num_channel_values,
                       float scale)
      : input_layout(input_layout),
        output_layout(output_layout),
        channel_values(channel_values),
        num_channel_values(num_channel_values),
        scale(scale) {
  }

  std::string DebugString() const {
    return base::StringPrintf(
        "Input Layout: %d, Output Layout %d, Scale: %f", input_layout,
        output_layout, scale);
  }

  ChannelLayout input_layout;
  ChannelLayout output_layout;
  float* channel_values;
  int num_channel_values;
  float scale;
};

std::ostream& operator<<(std::ostream& os, const ChannelMixerTestData& data) {
  return os << data.DebugString();
}

class ChannelMixerTest : public testing::TestWithParam<ChannelMixerTestData> {};

// Verify channels are mixed and scaled correctly.  The test only works if all
// output channels have the same value.
TEST_P(ChannelMixerTest, Mixing) {
  ChannelLayout input_layout = GetParam().input_layout;
  ChannelLayout output_layout = GetParam().output_layout;

  ChannelMixer mixer(input_layout, output_layout);
  scoped_ptr<AudioBus> input_bus = AudioBus::Create(
      ChannelLayoutToChannelCount(input_layout), kFrames);
  scoped_ptr<AudioBus> output_bus = AudioBus::Create(
      ChannelLayoutToChannelCount(output_layout), kFrames);

  const float* channel_values = GetParam().channel_values;
  ASSERT_EQ(input_bus->channels(), GetParam().num_channel_values);

  float expected_value = 0;
  float scale = GetParam().scale;
  for (int ch = 0; ch < input_bus->channels(); ++ch) {
    std::fill(input_bus->channel(ch), input_bus->channel(ch) + kFrames,
              channel_values[ch]);
    expected_value += channel_values[ch] * scale;
  }

  mixer.Transform(input_bus.get(), output_bus.get());

  for (int ch = 0; ch < output_bus->channels(); ++ch) {
    for (int frame = 0; frame < output_bus->frames(); ++frame) {
      ASSERT_FLOAT_EQ(output_bus->channel(ch)[frame], expected_value);
    }
  }
}

static float kStereoToMonoValues[] = { 0.5f, 0.75f };
static float kMonoToStereoValues[] = { 0.5f };
// Zero the center channel since it will be mixed at scale 1 vs M_SQRT1_2.
static float kFiveOneToMonoValues[] = { 0.1f, 0.2f, 0.0f, 0.4f, 0.5f, 0.6f };

// Run through basic sanity tests for some common conversions.
INSTANTIATE_TEST_CASE_P(ChannelMixerTest, ChannelMixerTest, testing::Values(
    ChannelMixerTestData(CHANNEL_LAYOUT_STEREO, CHANNEL_LAYOUT_MONO,
                         kStereoToMonoValues, arraysize(kStereoToMonoValues),
                         0.5f),
    ChannelMixerTestData(CHANNEL_LAYOUT_MONO, CHANNEL_LAYOUT_STEREO,
                         kMonoToStereoValues, arraysize(kMonoToStereoValues),
                         1.0f),
    ChannelMixerTestData(CHANNEL_LAYOUT_5_1, CHANNEL_LAYOUT_MONO,
                         kFiveOneToMonoValues, arraysize(kFiveOneToMonoValues),
                         static_cast<float>(M_SQRT1_2))
));

}  // namespace media