blob: 989b674491e88010cc2ffe0e142db8fc1d8dde81 [file] [log] [blame]
[email protected]a6ccb7722012-10-23 21:10:431// 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 get M_PI.
6#define _USE_MATH_DEFINES
sergeyu42ad7c02015-12-24 00:20:517
8#include "remoting/codec/audio_encoder_opus.h"
9
[email protected]a6ccb7722012-10-23 21:10:4310#include <math.h>
avi5a080f012015-12-22 23:15:4311#include <stddef.h>
12#include <stdint.h>
[email protected]a6ccb7722012-10-23 21:10:4313
sergeyu42ad7c02015-12-24 00:20:5114#include <utility>
[email protected]a6ccb7722012-10-23 21:10:4315
16#include "base/logging.h"
17#include "remoting/codec/audio_decoder_opus.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20namespace remoting {
21
22namespace {
23
24// Maximum value that can be encoded in a 16-bit signed sample.
25const int kMaxSampleValue = 32767;
26
27const int kChannels = 2;
28
29// Phase shift between left and right channels.
30const double kChannelPhaseShift = 2 * M_PI / 3;
31
32// The sampling rate that OPUS uses internally and that we expect to get
33// from the decoder.
34const AudioPacket_SamplingRate kDefaultSamplingRate =
35 AudioPacket::SAMPLING_RATE_48000;
36
37// Maximum latency expected from the encoder.
38const int kMaxLatencyMs = 40;
39
40// When verifying results ignore the first 1k samples. This is necessary because
41// it takes some time for the codec to adjust for the input signal.
42const int kSkippedFirstSamples = 1000;
43
44// Maximum standard deviation of the difference between original and decoded
45// signals as a proportion of kMaxSampleValue. For two unrelated signals this
46// difference will be close to 1.0, even for signals that differ only slightly.
47// The value is chosen such that all the tests pass normally, but fail with
48// small changes (e.g. one sample shift between signals).
49const double kMaxSignalDeviation = 0.1;
50
51} // namespace
52
53class OpusAudioEncoderTest : public testing::Test {
54 public:
55 // Return test signal value at the specified position |pos|. |frequency_hz|
56 // defines frequency of the signal. |channel| is used to calculate phase shift
57 // of the signal, so that different signals are generated for left and right
58 // channels.
avi5a080f012015-12-22 23:15:4359 static int16_t GetSampleValue(AudioPacket::SamplingRate rate,
60 double frequency_hz,
61 double pos,
62 int channel) {
[email protected]a6ccb7722012-10-23 21:10:4363 double angle = pos * 2 * M_PI * frequency_hz / rate +
64 kChannelPhaseShift * channel;
65 return static_cast<int>(sin(angle) * kMaxSampleValue + 0.5);
66 }
67
68 // Creates audio packet filled with a test signal with the specified
69 // |frequency_hz|.
dcheng0765c492016-04-06 22:41:5370 std::unique_ptr<AudioPacket> CreatePacket(int samples,
71 AudioPacket::SamplingRate rate,
72 double frequency_hz,
73 int pos) {
avi5a080f012015-12-22 23:15:4374 std::vector<int16_t> data(samples * kChannels);
[email protected]a6ccb7722012-10-23 21:10:4375 for (int i = 0; i < samples; ++i) {
76 data[i * kChannels] = GetSampleValue(rate, frequency_hz, i + pos, 0);
77 data[i * kChannels + 1] = GetSampleValue(rate, frequency_hz, i + pos, 1);
78 }
79
dcheng0765c492016-04-06 22:41:5380 std::unique_ptr<AudioPacket> packet(new AudioPacket());
[email protected]a6ccb7722012-10-23 21:10:4381 packet->add_data(reinterpret_cast<char*>(&(data[0])),
avi5a080f012015-12-22 23:15:4382 samples * kChannels * sizeof(int16_t));
[email protected]a6ccb7722012-10-23 21:10:4383 packet->set_encoding(AudioPacket::ENCODING_RAW);
84 packet->set_sampling_rate(rate);
85 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
86 packet->set_channels(AudioPacket::CHANNELS_STEREO);
sergeyu42ad7c02015-12-24 00:20:5187 return packet;
[email protected]a6ccb7722012-10-23 21:10:4388 }
89
90 // Decoded data is normally shifted in phase relative to the original signal.
91 // This function returns the approximate shift in samples by finding the first
92 // point when signal goes from negative to positive.
avi5a080f012015-12-22 23:15:4393 double EstimateSignalShift(const std::vector<int16_t>& received_data) {
[email protected]a6ccb7722012-10-23 21:10:4394 for (size_t i = kSkippedFirstSamples;
95 i < received_data.size() / kChannels - 1; i++) {
avi5a080f012015-12-22 23:15:4396 int16_t this_sample = received_data[i * kChannels];
97 int16_t next_sample = received_data[(i + 1) * kChannels];
[email protected]a6ccb7722012-10-23 21:10:4398 if (this_sample < 0 && next_sample > 0) {
99 return
100 i + static_cast<double>(-this_sample) / (next_sample - this_sample);
101 }
102 }
103 return 0;
104 }
105
106 // Compares decoded signal with the test signal that was encoded. It estimates
107 // phase shift from the original signal, then calculates standard deviation of
108 // the difference between original and decoded signals.
109 void ValidateReceivedData(int samples,
110 AudioPacket::SamplingRate rate,
111 double frequency_hz,
avi5a080f012015-12-22 23:15:43112 const std::vector<int16_t>& received_data) {
[email protected]a6ccb7722012-10-23 21:10:43113 double shift = EstimateSignalShift(received_data);
114 double diff_sqare_sum = 0;
115 for (size_t i = kSkippedFirstSamples;
116 i < received_data.size() / kChannels; i++) {
117 double d = received_data[i * kChannels] -
118 GetSampleValue(rate, frequency_hz, i - shift, 0);
119 diff_sqare_sum += d * d;
120 d = received_data[i * kChannels + 1] -
121 GetSampleValue(rate, frequency_hz, i - shift, 1);
122 diff_sqare_sum += d * d;
123 }
124 double deviation = sqrt(diff_sqare_sum / received_data.size())
125 / kMaxSampleValue;
[email protected]b4f63c02013-03-02 01:59:58126 LOG(ERROR) << "Decoded signal deviation: " << deviation;
[email protected]a6ccb7722012-10-23 21:10:43127 EXPECT_LE(deviation, kMaxSignalDeviation);
128 }
129
130 void TestEncodeDecode(int packet_size,
131 double frequency_hz,
132 AudioPacket::SamplingRate rate) {
133 const int kTotalTestSamples = 24000;
134
135 encoder_.reset(new AudioEncoderOpus());
136 decoder_.reset(new AudioDecoderOpus());
137
avi5a080f012015-12-22 23:15:43138 std::vector<int16_t> received_data;
[email protected]a6ccb7722012-10-23 21:10:43139 int pos = 0;
140 for (; pos < kTotalTestSamples; pos += packet_size) {
dcheng0765c492016-04-06 22:41:53141 std::unique_ptr<AudioPacket> source_packet =
142 CreatePacket(packet_size, rate, frequency_hz, pos);
143 std::unique_ptr<AudioPacket> encoded =
144 encoder_->Encode(std::move(source_packet));
145 if (encoded.get()) {
146 std::unique_ptr<AudioPacket> decoded =
147 decoder_->Decode(std::move(encoded));
148 EXPECT_EQ(kDefaultSamplingRate, decoded->sampling_rate());
149 for (int i = 0; i < decoded->data_size(); ++i) {
150 const int16_t* data =
151 reinterpret_cast<const int16_t*>(decoded->data(i).data());
152 received_data.insert(
153 received_data.end(), data,
154 data + decoded->data(i).size() / sizeof(int16_t));
155 }
[email protected]a6ccb7722012-10-23 21:10:43156 }
157 }
158
159 // Verify that at most kMaxLatencyMs worth of samples is buffered inside
160 // |encoder_| and |decoder_|.
161 EXPECT_GE(static_cast<int>(received_data.size()) / kChannels,
162 pos - rate * kMaxLatencyMs / 1000);
163
164 ValidateReceivedData(packet_size, kDefaultSamplingRate,
165 frequency_hz, received_data);
166 }
167
168 protected:
dcheng0765c492016-04-06 22:41:53169 std::unique_ptr<AudioEncoderOpus> encoder_;
170 std::unique_ptr<AudioDecoderOpus> decoder_;
[email protected]a6ccb7722012-10-23 21:10:43171};
172
173TEST_F(OpusAudioEncoderTest, CreateAndDestroy) {
174}
175
176TEST_F(OpusAudioEncoderTest, NoResampling) {
177 TestEncodeDecode(2000, 50, AudioPacket::SAMPLING_RATE_48000);
178 TestEncodeDecode(2000, 3000, AudioPacket::SAMPLING_RATE_48000);
179 TestEncodeDecode(2000, 10000, AudioPacket::SAMPLING_RATE_48000);
180}
181
182TEST_F(OpusAudioEncoderTest, Resampling) {
183 TestEncodeDecode(2000, 50, AudioPacket::SAMPLING_RATE_44100);
184 TestEncodeDecode(2000, 3000, AudioPacket::SAMPLING_RATE_44100);
185 TestEncodeDecode(2000, 10000, AudioPacket::SAMPLING_RATE_44100);
186}
187
188TEST_F(OpusAudioEncoderTest, BufferSizeAndResampling) {
189 TestEncodeDecode(500, 3000, AudioPacket::SAMPLING_RATE_44100);
190 TestEncodeDecode(1000, 3000, AudioPacket::SAMPLING_RATE_44100);
191 TestEncodeDecode(5000, 3000, AudioPacket::SAMPLING_RATE_44100);
192}
193
194} // namespace remoting