1// Copyright 2014 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#include "base/memory/scoped_ptr.h"
6#include "media/base/audio_buffer.h"
7#include "media/base/audio_buffer_converter.h"
8#include "media/base/sinc_resampler.h"
9#include "media/base/test_helpers.h"
10#include "testing/gmock/include/gmock/gmock.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13namespace media {
14
15// Important: Use an odd buffer size here so SIMD issues are caught.
16const int kOutFrameSize = 441;
17const int kOutSampleRate = 44100;
18const ChannelLayout kOutChannelLayout = CHANNEL_LAYOUT_STEREO;
19const int kOutChannelCount = 2;
20
21static scoped_refptr<AudioBuffer> MakeTestBuffer(int sample_rate,
22                                                 ChannelLayout channel_layout,
23                                                 int channel_count,
24                                                 int frames) {
25  return MakeAudioBuffer<uint8>(kSampleFormatU8,
26                                channel_layout,
27                                channel_count,
28                                sample_rate,
29                                0,
30                                1,
31                                frames,
32                                base::TimeDelta::FromSeconds(0));
33}
34
35class AudioBufferConverterTest : public ::testing::Test {
36 public:
37  AudioBufferConverterTest()
38      : input_frames_(0),
39        expected_output_frames_(0.0),
40        output_frames_(0),
41        output_params_(AudioParameters::AUDIO_PCM_LOW_LATENCY,
42                       kOutChannelLayout,
43                       kOutSampleRate,
44                       16,
45                       kOutFrameSize) {
46    audio_buffer_converter_.reset(new AudioBufferConverter(output_params_));
47  }
48
49  void Reset() {
50    audio_buffer_converter_->Reset();
51    output_frames_ = expected_output_frames_ = input_frames_ = 0;
52  }
53
54  void AddInput(const scoped_refptr<AudioBuffer>& in) {
55    if (!in->end_of_stream()) {
56      input_frames_ += in->frame_count();
57      expected_output_frames_ +=
58          in->frame_count() *
59          (static_cast<double>(output_params_.sample_rate()) /
60           in->sample_rate());
61    }
62    audio_buffer_converter_->AddInput(in);
63  }
64
65  void ConsumeOutput() {
66    ASSERT_TRUE(audio_buffer_converter_->HasNextBuffer());
67    scoped_refptr<AudioBuffer> out = audio_buffer_converter_->GetNextBuffer();
68    if (!out->end_of_stream()) {
69      output_frames_ += out->frame_count();
70      EXPECT_EQ(out->sample_rate(), output_params_.sample_rate());
71      EXPECT_EQ(out->channel_layout(), output_params_.channel_layout());
72      EXPECT_EQ(out->channel_count(), output_params_.channels());
73    } else {
74      EXPECT_FALSE(audio_buffer_converter_->HasNextBuffer());
75    }
76  }
77
78  void ConsumeAllOutput() {
79    AddInput(AudioBuffer::CreateEOSBuffer());
80    while (audio_buffer_converter_->HasNextBuffer())
81      ConsumeOutput();
82    EXPECT_EQ(output_frames_, ceil(expected_output_frames_));
83  }
84
85 protected:
86  scoped_ptr<AudioBufferConverter> audio_buffer_converter_;
87
88  int input_frames_;
89  double expected_output_frames_;
90  int output_frames_;
91  int input_buffers_;
92  AudioParameters output_params_;
93};
94
95TEST_F(AudioBufferConverterTest, PassThrough) {
96  scoped_refptr<AudioBuffer> in =
97      MakeTestBuffer(kOutSampleRate, kOutChannelLayout, kOutChannelCount, 512);
98  AddInput(in);
99  ConsumeAllOutput();
100}
101
102TEST_F(AudioBufferConverterTest, Downsample) {
103  scoped_refptr<AudioBuffer> in =
104      MakeTestBuffer(48000, kOutChannelLayout, kOutChannelCount, 512);
105  AddInput(in);
106  ConsumeAllOutput();
107}
108
109TEST_F(AudioBufferConverterTest, Upsample) {
110  scoped_refptr<AudioBuffer> in =
111      MakeTestBuffer(8000, kOutChannelLayout, kOutChannelCount, 512);
112  AddInput(in);
113  ConsumeAllOutput();
114}
115
116// Test resampling a buffer smaller than the SincResampler's kernel size.
117TEST_F(AudioBufferConverterTest, Resample_TinyBuffer) {
118  AddInput(MakeTestBuffer(
119      48000, CHANNEL_LAYOUT_STEREO, 2, SincResampler::kKernelSize - 1));
120  ConsumeAllOutput();
121}
122
123TEST_F(AudioBufferConverterTest, Resample_DifferingBufferSizes) {
124  const int input_sample_rate = 48000;
125  AddInput(MakeTestBuffer(
126      input_sample_rate, kOutChannelLayout, kOutChannelCount, 100));
127  AddInput(MakeTestBuffer(
128      input_sample_rate, kOutChannelLayout, kOutChannelCount, 200));
129  AddInput(MakeTestBuffer(
130      input_sample_rate, kOutChannelLayout, kOutChannelCount, 300));
131  AddInput(MakeTestBuffer(
132      input_sample_rate, kOutChannelLayout, kOutChannelCount, 400));
133  AddInput(MakeTestBuffer(
134      input_sample_rate, kOutChannelLayout, kOutChannelCount, 500));
135  ConsumeAllOutput();
136}
137
138TEST_F(AudioBufferConverterTest, ChannelDownmix) {
139  scoped_refptr<AudioBuffer> in =
140      MakeTestBuffer(kOutSampleRate, CHANNEL_LAYOUT_MONO, 1, 512);
141  AddInput(in);
142  ConsumeAllOutput();
143}
144
145TEST_F(AudioBufferConverterTest, ChannelUpmix) {
146  scoped_refptr<AudioBuffer> in =
147      MakeTestBuffer(kOutSampleRate, CHANNEL_LAYOUT_5_1, 6, 512);
148  AddInput(in);
149  ConsumeAllOutput();
150}
151
152TEST_F(AudioBufferConverterTest, ResampleAndRemix) {
153  scoped_refptr<AudioBuffer> in =
154      MakeTestBuffer(48000, CHANNEL_LAYOUT_5_1, 6, 512);
155  AddInput(in);
156  ConsumeAllOutput();
157}
158
159TEST_F(AudioBufferConverterTest, ConfigChange_SampleRate) {
160  AddInput(MakeTestBuffer(48000, kOutChannelLayout, kOutChannelCount, 512));
161  AddInput(MakeTestBuffer(44100, kOutChannelLayout, kOutChannelCount, 512));
162  ConsumeAllOutput();
163}
164
165TEST_F(AudioBufferConverterTest, ConfigChange_ChannelLayout) {
166  AddInput(MakeTestBuffer(kOutSampleRate, CHANNEL_LAYOUT_STEREO, 2, 512));
167  AddInput(MakeTestBuffer(kOutSampleRate, CHANNEL_LAYOUT_MONO, 1, 512));
168  ConsumeAllOutput();
169}
170
171TEST_F(AudioBufferConverterTest, ConfigChange_SampleRateAndChannelLayout) {
172  AddInput(MakeTestBuffer(44100, CHANNEL_LAYOUT_STEREO, 2, 512));
173  AddInput(MakeTestBuffer(48000, CHANNEL_LAYOUT_MONO, 1, 512));
174  ConsumeAllOutput();
175}
176
177TEST_F(AudioBufferConverterTest, ConfigChange_Multiple) {
178  AddInput(MakeTestBuffer(44100, CHANNEL_LAYOUT_STEREO, 2, 512));
179  AddInput(MakeTestBuffer(48000, CHANNEL_LAYOUT_MONO, 1, 512));
180  AddInput(MakeTestBuffer(44100, CHANNEL_LAYOUT_5_1, 6, 512));
181  AddInput(MakeTestBuffer(22050, CHANNEL_LAYOUT_STEREO, 2, 512));
182  ConsumeAllOutput();
183}
184
185TEST_F(AudioBufferConverterTest, Reset) {
186  AddInput(MakeTestBuffer(44100, CHANNEL_LAYOUT_STEREO, 2, 512));
187  Reset();
188  ConsumeAllOutput();
189}
190
191TEST_F(AudioBufferConverterTest, ResampleThenReset) {
192  // Resampling is likely to leave some data buffered in AudioConverter's
193  // fifo or resampler, so make sure Reset() cleans that all up.
194  AddInput(MakeTestBuffer(48000, CHANNEL_LAYOUT_STEREO, 2, 512));
195  Reset();
196  ConsumeAllOutput();
197}
198
199TEST_F(AudioBufferConverterTest, ResetThenConvert) {
200  AddInput(
201      MakeTestBuffer(kOutSampleRate, kOutChannelLayout, kOutChannelCount, 512));
202  Reset();
203  // Make sure we can keep using the AudioBufferConverter after we've Reset().
204  AddInput(
205      MakeTestBuffer(kOutSampleRate, kOutChannelLayout, kOutChannelCount, 512));
206  ConsumeAllOutput();
207}
208
209TEST_F(AudioBufferConverterTest, DiscreteChannelLayout) {
210  output_params_ = AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
211                                   CHANNEL_LAYOUT_DISCRETE,
212                                   2,
213                                   kOutSampleRate,
214                                   16,
215                                   512,
216                                   0);
217  audio_buffer_converter_.reset(new AudioBufferConverter(output_params_));
218  AddInput(MakeTestBuffer(kOutSampleRate, CHANNEL_LAYOUT_STEREO, 2, 512));
219  ConsumeAllOutput();
220}
221
222TEST_F(AudioBufferConverterTest, LargeBuffersResampling) {
223  output_params_ = AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
224                                   kOutChannelLayout,
225                                   kOutSampleRate,
226                                   16,
227                                   2048);
228
229  audio_buffer_converter_.reset(new AudioBufferConverter(output_params_));
230  const int kInputSampleRate = 48000;
231  const int kInputFrameSize = 8192;
232  ASSERT_NE(kInputSampleRate, kOutSampleRate);
233
234  const int kInputBuffers = 3;
235  for (int i = 0; i < kInputBuffers; ++i) {
236    AddInput(MakeTestBuffer(kInputSampleRate,
237                            kOutChannelLayout,
238                            kOutChannelCount,
239                            kInputFrameSize));
240  }
241
242  // Do not add an EOS packet here, as it will invoke flushing.
243  while (audio_buffer_converter_->HasNextBuffer())
244    ConsumeOutput();
245
246  // Since the input buffer size is a multiple of the input request size there
247  // should never be any frames remaining at this point.
248  ASSERT_EQ(kInputFrameSize %
249                audio_buffer_converter_->input_buffer_size_for_testing(),
250            0);
251  EXPECT_EQ(0, audio_buffer_converter_->input_frames_left_for_testing());
252}
253
254}  // namespace media
255