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                               0,
    111                               AudioParameters::kAudioCDSampleRate, 16,
    112                               kFrames,
    113                               AudioParameters::NO_EFFECTS);
    114 
    115   ChannelLayout output_layout = GetParam().output_layout;
    116   int output_channels = GetParam().output_channels;
    117   scoped_ptr<AudioBus> output_bus = AudioBus::Create(output_channels, kFrames);
    118   AudioParameters output_audio(AudioParameters::AUDIO_PCM_LINEAR,
    119                                output_layout,
    120                                output_layout == CHANNEL_LAYOUT_DISCRETE ?
    121                                   output_channels :
    122                                   ChannelLayoutToChannelCount(output_layout),
    123                                0,
    124                                AudioParameters::kAudioCDSampleRate, 16,
    125                                kFrames,
    126                                AudioParameters::NO_EFFECTS);
    127 
    128   const float* channel_values = GetParam().channel_values;
    129   ASSERT_EQ(input_bus->channels(), GetParam().num_channel_values);
    130 
    131   float expected_value = 0;
    132   float scale = GetParam().scale;
    133   for (int ch = 0; ch < input_bus->channels(); ++ch) {
    134     std::fill(input_bus->channel(ch), input_bus->channel(ch) + kFrames,
    135               channel_values[ch]);
    136     expected_value += channel_values[ch] * scale;
    137   }
    138 
    139   ChannelMixer mixer(input_audio, output_audio);
    140   mixer.Transform(input_bus.get(), output_bus.get());
    141 
    142   // Validate the output channel
    143   if (input_layout != CHANNEL_LAYOUT_DISCRETE) {
    144     for (int ch = 0; ch < output_bus->channels(); ++ch) {
    145       for (int frame = 0; frame < output_bus->frames(); ++frame) {
    146         ASSERT_FLOAT_EQ(output_bus->channel(ch)[frame], expected_value);
    147       }
    148     }
    149   } else {
    150     // Processing discrete mixing. If there is a matching input channel,
    151     // then the output channel should be set. If no input channel,
    152     // output channel should be 0
    153     for (int ch = 0; ch < output_bus->channels(); ++ch) {
    154       expected_value = (ch < input_channels) ? channel_values[ch] : 0;
    155       for (int frame = 0; frame < output_bus->frames(); ++frame) {
    156         ASSERT_FLOAT_EQ(output_bus->channel(ch)[frame], expected_value);
    157       }
    158     }
    159   }
    160 }
    161 
    162 static float kStereoToMonoValues[] = { 0.5f, 0.75f };
    163 static float kMonoToStereoValues[] = { 0.5f };
    164 // Zero the center channel since it will be mixed at scale 1 vs M_SQRT1_2.
    165 static float kFiveOneToMonoValues[] = { 0.1f, 0.2f, 0.0f, 0.4f, 0.5f, 0.6f };
    166 static float kFiveDiscreteValues[] = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f };
    167 
    168 // Run through basic sanity tests for some common conversions.
    169 INSTANTIATE_TEST_CASE_P(ChannelMixerTest, ChannelMixerTest, testing::Values(
    170     ChannelMixerTestData(CHANNEL_LAYOUT_STEREO, CHANNEL_LAYOUT_MONO,
    171                          kStereoToMonoValues, arraysize(kStereoToMonoValues),
    172                          0.5f),
    173     ChannelMixerTestData(CHANNEL_LAYOUT_MONO, CHANNEL_LAYOUT_STEREO,
    174                          kMonoToStereoValues, arraysize(kMonoToStereoValues),
    175                          1.0f),
    176     ChannelMixerTestData(CHANNEL_LAYOUT_5_1, CHANNEL_LAYOUT_MONO,
    177                          kFiveOneToMonoValues, arraysize(kFiveOneToMonoValues),
    178                          static_cast<float>(M_SQRT1_2)),
    179     ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 2,
    180                          CHANNEL_LAYOUT_DISCRETE, 2,
    181                          kStereoToMonoValues, arraysize(kStereoToMonoValues)),
    182     ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 2,
    183                          CHANNEL_LAYOUT_DISCRETE, 5,
    184                          kStereoToMonoValues, arraysize(kStereoToMonoValues)),
    185     ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 5,
    186                          CHANNEL_LAYOUT_DISCRETE, 2,
    187                          kFiveDiscreteValues, arraysize(kFiveDiscreteValues))
    188 ));
    189 
    190 }  // namespace media
    191