Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // MSVC++ requires this to be set before any other includes to get M_SQRT1_2.
      6 #define _USE_MATH_DEFINES
      7 
      8 #include <cmath>
      9 
     10 #include "base/strings/stringprintf.h"
     11 #include "media/audio/audio_parameters.h"
     12 #include "media/base/audio_bus.h"
     13 #include "media/base/channel_mixer.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 namespace media {
     17 
     18 // Number of frames to test with.
     19 enum { kFrames = 16 };
     20 
     21 // Test all possible layout conversions can be constructed and mixed.
     22 TEST(ChannelMixerTest, ConstructAllPossibleLayouts) {
     23   for (ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
     24        input_layout <= CHANNEL_LAYOUT_MAX;
     25        input_layout = static_cast<ChannelLayout>(input_layout + 1)) {
     26     for (ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
     27          output_layout < CHANNEL_LAYOUT_STEREO_DOWNMIX;
     28          output_layout = static_cast<ChannelLayout>(output_layout + 1)) {
     29       // DISCRETE can't be tested here based on the current approach.
     30       // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC is not mixable.
     31       if (input_layout == CHANNEL_LAYOUT_DISCRETE ||
     32           input_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC ||
     33           output_layout == CHANNEL_LAYOUT_DISCRETE ||
     34           output_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
     35         continue;
     36       }
     37 
     38       SCOPED_TRACE(base::StringPrintf(
     39           "Input Layout: %d, Output Layout: %d", input_layout, output_layout));
     40       ChannelMixer mixer(input_layout, output_layout);
     41       scoped_ptr<AudioBus> input_bus = AudioBus::Create(
     42           ChannelLayoutToChannelCount(input_layout), kFrames);
     43       scoped_ptr<AudioBus> output_bus = AudioBus::Create(
     44           ChannelLayoutToChannelCount(output_layout), kFrames);
     45       for (int ch = 0; ch < input_bus->channels(); ++ch)
     46         std::fill(input_bus->channel(ch), input_bus->channel(ch) + kFrames, 1);
     47 
     48       mixer.Transform(input_bus.get(), output_bus.get());
     49     }
     50   }
     51 }
     52 
     53 struct ChannelMixerTestData {
     54   ChannelMixerTestData(ChannelLayout input_layout, ChannelLayout output_layout,
     55                        float* channel_values, int num_channel_values,
     56                        float scale)
     57       : input_layout(input_layout),
     58         output_layout(output_layout),
     59         channel_values(channel_values),
     60         num_channel_values(num_channel_values),
     61         scale(scale) {
     62     input_channels = ChannelLayoutToChannelCount(input_layout);
     63     output_channels = ChannelLayoutToChannelCount(output_layout);
     64   }
     65 
     66   ChannelMixerTestData(ChannelLayout input_layout, int input_channels,
     67                        ChannelLayout output_layout, int output_channels,
     68                        float* channel_values, int num_channel_values)
     69       : input_layout(input_layout),
     70         input_channels(input_channels),
     71         output_layout(output_layout),
     72         output_channels(output_channels),
     73         channel_values(channel_values),
     74         num_channel_values(num_channel_values),
     75         scale(1.0f) {
     76   }
     77 
     78   std::string DebugString() const {
     79     return base::StringPrintf(
     80         "Input Layout: %d, Output Layout %d, Scale: %f", input_layout,
     81         output_layout, scale);
     82   }
     83 
     84   ChannelLayout input_layout;
     85   int input_channels;
     86   ChannelLayout output_layout;
     87   int output_channels;
     88   float* channel_values;
     89   int num_channel_values;
     90   float scale;
     91 };
     92 
     93 std::ostream& operator<<(std::ostream& os, const ChannelMixerTestData& data) {
     94   return os << data.DebugString();
     95 }
     96 
     97 class ChannelMixerTest : public testing::TestWithParam<ChannelMixerTestData> {};
     98 
     99 // Verify channels are mixed and scaled correctly.  The test only works if all
    100 // output channels have the same value.
    101 TEST_P(ChannelMixerTest, Mixing) {
    102   ChannelLayout input_layout = GetParam().input_layout;
    103   int input_channels = GetParam().input_channels;
    104   scoped_ptr<AudioBus> input_bus = AudioBus::Create(input_channels, kFrames);
    105   AudioParameters input_audio(AudioParameters::AUDIO_PCM_LINEAR,
    106                               input_layout,
    107                               input_layout == CHANNEL_LAYOUT_DISCRETE ?
    108                                   input_channels :
    109                                   ChannelLayoutToChannelCount(input_layout),
    110                               AudioParameters::kAudioCDSampleRate, 16,
    111                               kFrames,
    112                               AudioParameters::NO_EFFECTS);
    113 
    114   ChannelLayout output_layout = GetParam().output_layout;
    115   int output_channels = GetParam().output_channels;
    116   scoped_ptr<AudioBus> output_bus = AudioBus::Create(output_channels, kFrames);
    117   AudioParameters output_audio(AudioParameters::AUDIO_PCM_LINEAR,
    118                                output_layout,
    119                                output_layout == CHANNEL_LAYOUT_DISCRETE ?
    120                                    output_channels :
    121                                    ChannelLayoutToChannelCount(output_layout),
    122                                AudioParameters::kAudioCDSampleRate, 16,
    123                                kFrames,
    124                                AudioParameters::NO_EFFECTS);
    125 
    126   const float* channel_values = GetParam().channel_values;
    127   ASSERT_EQ(input_bus->channels(), GetParam().num_channel_values);
    128 
    129   float expected_value = 0;
    130   float scale = GetParam().scale;
    131   for (int ch = 0; ch < input_bus->channels(); ++ch) {
    132     std::fill(input_bus->channel(ch), input_bus->channel(ch) + kFrames,
    133               channel_values[ch]);
    134     expected_value += channel_values[ch] * scale;
    135   }
    136 
    137   ChannelMixer mixer(input_audio, output_audio);
    138   mixer.Transform(input_bus.get(), output_bus.get());
    139 
    140   // Validate the output channel
    141   if (input_layout != CHANNEL_LAYOUT_DISCRETE) {
    142     for (int ch = 0; ch < output_bus->channels(); ++ch) {
    143       for (int frame = 0; frame < output_bus->frames(); ++frame) {
    144         ASSERT_FLOAT_EQ(output_bus->channel(ch)[frame], expected_value);
    145       }
    146     }
    147   } else {
    148     // Processing discrete mixing. If there is a matching input channel,
    149     // then the output channel should be set. If no input channel,
    150     // output channel should be 0
    151     for (int ch = 0; ch < output_bus->channels(); ++ch) {
    152       expected_value = (ch < input_channels) ? channel_values[ch] : 0;
    153       for (int frame = 0; frame < output_bus->frames(); ++frame) {
    154         ASSERT_FLOAT_EQ(output_bus->channel(ch)[frame], expected_value);
    155       }
    156     }
    157   }
    158 }
    159 
    160 static float kStereoToMonoValues[] = { 0.5f, 0.75f };
    161 static float kMonoToStereoValues[] = { 0.5f };
    162 // Zero the center channel since it will be mixed at scale 1 vs M_SQRT1_2.
    163 static float kFiveOneToMonoValues[] = { 0.1f, 0.2f, 0.0f, 0.4f, 0.5f, 0.6f };
    164 static float kFiveDiscreteValues[] = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f };
    165 
    166 // Run through basic sanity tests for some common conversions.
    167 INSTANTIATE_TEST_CASE_P(ChannelMixerTest, ChannelMixerTest, testing::Values(
    168     ChannelMixerTestData(CHANNEL_LAYOUT_STEREO, CHANNEL_LAYOUT_MONO,
    169                          kStereoToMonoValues, arraysize(kStereoToMonoValues),
    170                          0.5f),
    171     ChannelMixerTestData(CHANNEL_LAYOUT_MONO, CHANNEL_LAYOUT_STEREO,
    172                          kMonoToStereoValues, arraysize(kMonoToStereoValues),
    173                          1.0f),
    174     ChannelMixerTestData(CHANNEL_LAYOUT_5_1, CHANNEL_LAYOUT_MONO,
    175                          kFiveOneToMonoValues, arraysize(kFiveOneToMonoValues),
    176                          static_cast<float>(M_SQRT1_2)),
    177     ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 2,
    178                          CHANNEL_LAYOUT_DISCRETE, 2,
    179                          kStereoToMonoValues, arraysize(kStereoToMonoValues)),
    180     ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 2,
    181                          CHANNEL_LAYOUT_DISCRETE, 5,
    182                          kStereoToMonoValues, arraysize(kStereoToMonoValues)),
    183     ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 5,
    184                          CHANNEL_LAYOUT_DISCRETE, 2,
    185                          kFiveDiscreteValues, arraysize(kFiveDiscreteValues))
    186 ));
    187 
    188 }  // namespace media
    189