Chromium Code Reviews| Index: remoting/codec/audio_encoder_opus_unittest.cc |
| diff --git a/remoting/codec/audio_encoder_opus_unittest.cc b/remoting/codec/audio_encoder_opus_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..810a8b0c0c58b45378b25890499305aa30acdaa5 |
| --- /dev/null |
| +++ b/remoting/codec/audio_encoder_opus_unittest.cc |
| @@ -0,0 +1,166 @@ |
| +// 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 get M_PI. |
| +#define _USE_MATH_DEFINES |
| +#include <math.h> |
| + |
| +#include "remoting/codec/audio_encoder_opus.h" |
| + |
| +#include "base/logging.h" |
| +#include "remoting/codec/audio_decoder_opus.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace remoting { |
| + |
| +namespace { |
| + |
| +const int kChannels = 2; |
| +const double kChannelPhaseShift = 2 * M_PI / 3; |
|
Wez
2012/10/22 22:50:21
nit: Add comments explaining what this is used for
Sergey Ulanov
2012/10/23 00:43:50
Done.
|
| +const AudioPacket_SamplingRate kDefaultSamplingRate = |
| + AudioPacket::SAMPLING_RATE_48000; |
| +const int kMaxLatencyMs = 40; |
| + |
| +// When verifying results ignore the first 1k samples. This is necessary because |
| +// it takes some time for the codec to adjust for the input signal. |
| +const int kSkippedFirstSamples = 1000; |
| + |
| +} // namespace |
| + |
| +class OpusAudioEncoderTest : public testing::Test { |
| + public: |
| + |
| + static int16 GetSampleValue( |
| + AudioPacket::SamplingRate rate, |
| + double frequency, |
|
Wez
2012/10/22 22:50:21
nit: Specify units.
Sergey Ulanov
2012/10/23 00:43:50
Done.
|
| + double pos, |
|
Wez
2012/10/22 22:50:21
nit: How can we have sub-sample position?
Sergey Ulanov
2012/10/23 00:43:50
That's used when comparing results - GetSignalShif
|
| + int channel) { |
| + double angle = pos * 2 * M_PI * frequency / rate + |
| + kChannelPhaseShift * channel; |
| + return static_cast<int>(sin(angle) * 32767 + 0.5); |
| + } |
| + |
| + scoped_ptr<AudioPacket> CreatePacket( |
| + int samples, |
| + AudioPacket::SamplingRate rate, |
| + double frequency, |
| + int pos) { |
| + |
| + std::vector<int16> data(samples * kChannels); |
|
Wez
2012/10/22 22:50:21
nit: Add a comment to explain that we're filling t
Sergey Ulanov
2012/10/23 00:43:50
Done.
|
| + for (int i = 0; i < samples; ++i) { |
| + data[i * kChannels] = GetSampleValue(rate, frequency, i + pos, 0); |
| + data[i * kChannels + 1] = GetSampleValue(rate, frequency, i + pos, 1); |
| + } |
| + |
| + scoped_ptr<AudioPacket> packet(new AudioPacket()); |
| + packet->add_data(reinterpret_cast<char*>(&(data[0])), |
| + samples * kChannels * sizeof(int16)); |
| + packet->set_encoding(AudioPacket::ENCODING_RAW); |
| + packet->set_sampling_rate(rate); |
| + packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); |
| + packet->set_channels(AudioPacket::CHANNELS_STEREO); |
| + return packet.Pass(); |
| + } |
| + |
| + // Decoded data is normally shifted in phase relative to the raw date. This |
|
Wez
2012/10/22 22:50:21
typo: date -> data
Sergey Ulanov
2012/10/23 00:43:50
Done.
|
| + // function returns approximate the phase difference by finding the first |
|
Wez
2012/10/22 22:50:21
typo: approximate the phase ... -> ... the approxi
Sergey Ulanov
2012/10/23 00:43:50
Done.
|
| + // point when signal goes from negative to positive. |
| + double GetSignalShift(const std::vector<int16>& received_data) { |
|
Wez
2012/10/22 22:50:21
nit: So this function is supposed to be getting th
Sergey Ulanov
2012/10/23 00:43:50
Renamed to EstimateSignalShift(). I don't think it
|
| + for (size_t i = kSkippedFirstSamples; |
| + i < received_data.size() / kChannels - 1; i++) { |
| + int16 this_sample = received_data[i * kChannels]; |
| + int16 next_sample = received_data[(i + 1) * kChannels]; |
| + if (this_sample < 0 && next_sample > 0) { |
| + return i + |
| + static_cast<double>(-this_sample) / (next_sample - this_sample); |
| + } |
| + } |
| + return 0; |
| + } |
| + |
| + void ValidateReceivedData(int samples, |
| + AudioPacket::SamplingRate rate, |
| + double frequency, |
| + const std::vector<int16>& received_data) { |
|
Wez
2012/10/22 22:50:21
nit: Add a comment explaining that we validate the
Sergey Ulanov
2012/10/23 00:43:50
Done.
|
| + double shift = GetSignalShift(received_data); |
| + double diff_sqare_sum = 0; |
| + for (size_t i = kSkippedFirstSamples; |
| + i < received_data.size() / kChannels; i++) { |
| + double d = received_data[i * kChannels] - |
| + GetSampleValue(rate, frequency, i - shift, 0); |
| + diff_sqare_sum += d * d; |
| + d = received_data[i * kChannels + 1] - |
| + GetSampleValue(rate, frequency, i - shift, 1); |
| + diff_sqare_sum += d * d; |
| + } |
| + double averate_difference = sqrt(diff_sqare_sum / received_data.size()); |
|
Wez
2012/10/22 22:50:21
typo: average_difference
Wez
2012/10/22 22:50:21
nit: Clarify the units you're using for the differ
Sergey Ulanov
2012/10/23 00:43:50
Done.
Sergey Ulanov
2012/10/23 00:43:50
Done.
|
| + EXPECT_LE(averate_difference, 5000); |
|
Wez
2012/10/22 22:50:21
nit: Consider moving 5000 to a constant, above
Sergey Ulanov
2012/10/23 00:43:50
Done.
|
| + } |
| + |
| + void ResetEncoder() { |
|
Wez
2012/10/22 22:50:21
nit: ResetEncoder -> Reset or ResetEncoderAndDecod
Sergey Ulanov
2012/10/23 00:43:50
Removed this function.
|
| + encoder_.reset(new AudioEncoderOpus()); |
| + decoder_.reset(new AudioDecoderOpus()); |
| + } |
| + |
| + void TestEncoderDecoder(int packet_size, |
|
Wez
2012/10/22 22:50:21
typo: TestEncodeDecode
Sergey Ulanov
2012/10/23 00:43:50
Done.
|
| + double frequency, |
| + AudioPacket::SamplingRate rate) { |
| + const int kTotalTestSamples = 24000; |
| + ResetEncoder(); |
| + |
| + std::vector<int16> received_data; |
| + int pos = 0; |
| + for (; pos < kTotalTestSamples; pos += packet_size) { |
| + scoped_ptr<AudioPacket> source_packet = |
| + CreatePacket(packet_size, rate, frequency, pos); |
| + scoped_ptr<AudioPacket> encoded = encoder_->Encode(source_packet.Pass()); |
|
Wez
2012/10/22 22:50:21
Line too long?
Sergey Ulanov
2012/10/23 00:43:50
Done.
|
| + if (encoded.get()) { |
|
Wez
2012/10/22 22:50:21
EXPECT(encoded.get())?
Sergey Ulanov
2012/10/23 00:43:50
Encoder is allowed to return NULL packet sometimes
|
| + scoped_ptr<AudioPacket> decoded = decoder_->Decode(encoded.Pass()); |
| + EXPECT_EQ(kDefaultSamplingRate, decoded->sampling_rate()); |
| + for (int i = 0; i < decoded->data_size(); ++i) { |
| + const int16* data = |
| + reinterpret_cast<const int16*>(decoded->data(i).data()); |
| + received_data.insert( |
| + received_data.end(), data, |
| + data + decoded->data(i).size() / sizeof(int16)); |
| + } |
| + } |
| + } |
| + |
| + // Verify that at most kMaxLatencyMs worth of samples is buffered inside |
| + // |encoder_| and |decoder_|. |
| + EXPECT_GE(static_cast<int>(received_data.size()) / kChannels, |
| + pos - rate * kMaxLatencyMs / 1000); |
| + |
| + ValidateReceivedData(packet_size, kDefaultSamplingRate, |
| + frequency, received_data); |
| + } |
| + |
| + protected: |
| + scoped_ptr<AudioEncoderOpus> encoder_; |
| + scoped_ptr<AudioDecoderOpus> decoder_; |
| +}; |
| + |
| +TEST_F(OpusAudioEncoderTest, CreateAndDestroy) { |
| +} |
| + |
| +TEST_F(OpusAudioEncoderTest, NoResampling) { |
| + TestEncoderDecoder(2000, 50, AudioPacket::SAMPLING_RATE_48000); |
| + TestEncoderDecoder(2000, 3000, AudioPacket::SAMPLING_RATE_48000); |
| + TestEncoderDecoder(2000, 10000, AudioPacket::SAMPLING_RATE_48000); |
| +} |
| + |
| +TEST_F(OpusAudioEncoderTest, Resampling) { |
| + TestEncoderDecoder(2000, 50, AudioPacket::SAMPLING_RATE_44100); |
| + TestEncoderDecoder(2000, 3000, AudioPacket::SAMPLING_RATE_44100); |
| + TestEncoderDecoder(2000, 10000, AudioPacket::SAMPLING_RATE_44100); |
| +} |
| + |
| +TEST_F(OpusAudioEncoderTest, BufferSize) { |
|
Wez
2012/10/22 22:50:21
nit: BufferingAndResampling / BufferSizeAndResampl
Sergey Ulanov
2012/10/23 00:43:50
Done.
|
| + TestEncoderDecoder(500, 3000, AudioPacket::SAMPLING_RATE_44100); |
| + TestEncoderDecoder(1000, 3000, AudioPacket::SAMPLING_RATE_44100); |
| + TestEncoderDecoder(5000, 3000, AudioPacket::SAMPLING_RATE_44100); |
|
Wez
2012/10/22 22:50:21
How long to these tests take?
Sergey Ulanov
2012/10/23 00:43:50
About 0.6 seconds total for all tests in this file
|
| +} |
| + |
| +} // namespace remoting |